Saltar al contenido

¿Cómo generar un UUID versión 4 (aleatorio) en Oracle?

Solución:

Aquí hay un ejemplo completo, basado en la respuesta de @Pablo Santa Cruz y el código que publicó.

No estoy seguro de por qué recibió un mensaje de error. Probablemente sea un problema con SQL Developer. Todo funciona bien cuando lo ejecuta en SQL * Plus y agrega una función:

   create or replace and compile
   java source named "RandomUUID"
   as
   public class RandomUUID
   {
      public static String create()
      {
              return java.util.UUID.randomUUID().toString();
      }
   }
   /
Java created.
   CREATE OR REPLACE FUNCTION RandomUUID
   RETURN VARCHAR2
   AS LANGUAGE JAVA
   NAME 'RandomUUID.create() return java.lang.String';
   /
Function created.
   select randomUUID() from dual;
RANDOMUUID()
--------------------------------------------------------------
4d3c8bdd-5379-4aeb-bc56-fcb01eb7cc33

Pero me quedaría con SYS_GUID si es posible. Mire el ID 1371805.1 en My Oracle Support: este error supuestamente se corrigió en 11.2.0.3.

EDITAR

Cuál es más rápido depende de cómo se utilicen las funciones.

Parece que la versión de Java es un poco más rápida cuando se usa en SQL. Sin embargo, si va a utilizar esta función en un contexto PL / SQL, la función PL / SQL es aproximadamente el doble de rápida. (Probablemente porque evita la sobrecarga de cambiar entre motores).

He aquí un ejemplo rápido:

--Create simple table
create table test1(a number);
insert into test1 select level from dual connect by level <= 100000;
commit;

--SQL Context: Java function is slightly faster
--
--PL/SQL: 2.979, 2.979, 2.964 seconds
--Java: 2.48, 2.465, 2.481 seconds
select count(*)
from test1
--where to_char(a) > random_uuid() --PL/SQL
where to_char(a) > RandomUUID() --Java
;

--PL/SQL Context: PL/SQL function is about twice as fast
--
--PL/SQL: 0.234, 0.218, 0.234
--Java: 0.52, 0.515, 0.53
declare
    v_test1 raw(30);
    v_test2 varchar2(36);
begin
    for i in 1 .. 10000 loop
        --v_test1 := random_uuid; --PL/SQL
        v_test2 := RandomUUID; --Java
    end loop;
end;
/

Los GUID de la versión 4 no son completamente aleatorio. Se supone que algunos de los bytes están arreglados. No estoy seguro de por qué se hizo esto, o si es importante, pero según https://www.cryptosys.net/pki/uuid-rfc4122.html:

El procedimiento para generar un UUID versión 4 es el siguiente:

Generate 16 random bytes (=128 bits)
Adjust certain bits according to RFC 4122 section 4.4 as follows:
    set the four most significant bits of the 7th byte to 0100'B, so the high nibble is "4"
    set the two most significant bits of the 9th byte to 10'B, so the high nibble will be one of "8", "9", "A", or "B".
Encode the adjusted bytes as 32 hexadecimal digits
Add four hyphen "-" characters to obtain blocks of 8, 4, 4, 4 and 12 hex digits
Output the resulting 36-character string "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"

Los valores de la versión de Java parecen ajustarse al estándar.

https://stackoverflow.com/a/10899320/1194307

La siguiente función usa sys_guid () y lo transforma en formato uuid:

create or replace function random_uuid return VARCHAR2 is
  v_uuid VARCHAR2(40);
begin
  select regexp_replace(rawtohex(sys_guid()), '([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})', '1-2-3-4-5') into v_uuid from dual;
  return v_uuid;
end random_uuid;

No es necesario crear el paquete dbms_crypto y otorgarlo.

Utilizo esto ahora como una solución alternativa:

create or replace function random_uuid return RAW is
  v_uuid RAW(16);
begin
  v_uuid := sys.dbms_crypto.randombytes(16);
  return (utl_raw.overlay(utl_raw.bit_or(utl_raw.bit_and(utl_raw.substr(v_uuid, 7, 1), '0F'), '40'), v_uuid, 7));
end random_uuid;

La función requiere dbms_crypto y utl_raw. Ambos requieren una subvención de ejecución.

grant execute on sys.dbms_crypto to uuid_user;
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *