sábado, 4 de abril de 2009

Columnas Auto-Incrementales en Oracle

La verdad es que sobre este tema podemos encontrar infinidad de comentarios en la red, no es demasiado complicado leer la opinión más extendida sobre el tema:

"¿Cómo puede ser que Oracle no disponga de un tipo de dato que se incremente automáticamente con cada nuevo registro?"

Y para los más experimentados, responderé a la pregunta: ¿Por qué merece la pena hablar de esto?

Por que no son pocos los desarrolladores que buscan información sobre este tema en internet, o que me han preguntado directamente.

Os presento las soluciones más "famosas" y sus ventajas e incovenientes:

Soluciones


Creamos una tabla, con un campo númerico como claver primaria:

create table T ( x int primary key, .... );


Creamos la secuencia:

create sequence t_seq;


La Elegante: Secuencia + Disparador
Crearemos un disparador que incrementará el valor del campo númerico:

create trigger t_trigger before insert on T for each row
begin
   if ( :new.x is null ) then
      select t_seq.nextval into :new.x from dual;
   end if;
end;
/

Y digo elegante por ser la que encontraremos en los libros.

La Válida: Aceptamos Barco (o Secuencia)
Cuando vayamos a insertar el registro, no dependeremos de un disparador, pero si utilizaremos la secuencia:

insert into T (x, ...) values (t_seq.nextval, ...);

Con esto perdemos algo de control sobre el valor que se introduce, ya que no podemos introducir condiciones o lógica de ningún tipo, pero no ahorramos los disparadores; algo no despreciable.

La NO Tan Buena: Máxmimo Valor del Campo
Si por un casual se nos ocurre hacer algo como esto:

create trigger t_trigger before insert on table_name for each row
begin
   select max(nvl(col_seq,0))+1 into :new.x
   from table_name ;
end ;
/

Saber que hasta que no finalice la transacción que contenga este disparador, no se actualizará la tabla, por lo que todas las transacciónes que se inicien de forma simultánea obtendrán el mismo valor. Y si el campo es clave primaria obtendremos un error de violacion de la clave única (unique constraint).

Opinión

Nos estamos acostumbrando a mezclar conceptos, nos hacemos la vida más sencilla pensando que debería ser lo "lógico"; cuando en realidad nos complicamos la vida. Señoras y señores, la respuesta es sencilla: las tablas tienen campos, los campos contienen datos y éstos pueden ser de varios tipos diferentes. Un campo numérico y otro de caracteres son diferentes; un campo numérico y otro fecha, son diferentes; un campo numérico y otro auto-incremental NO TINEN NINGUNA DIFERENCIA.

Si quiero que ocurra algo cuando se inserta un registro en una tabla, tengo que utilizar los disparadores (triggers), y eso no lo cuestiona nadie; es más, este sistema si que ha sido copiado por el resto de sgbd. Pero si quiero que se incremente automáticamente, parece que nos cueste encontrar la solución.

Si audiencia, lo más sencillo del mundo, yo mismo programo el disparador, pongo mis condiciones, controlo cuando quiero ejecutarlo o no, o simplemente lo desactivo. Más flexibilidad y opciones para los campos auto-incrementales es imposible.

Conclusión

Con esto espero que quede claro: la clave esta en la secuencia. Además podemos usar disparadores para tener un absoluto control sobre cuando y como se insertan los valores en nuestras tablas. Con cualquier otro sistema dependeremos de las funciones o mecanismos que nos ofrezca el sgbd y sus opciones para el control de los campos autonuméricos, pero nunca un control absoluto.

3 comentarios:

Anónimo dijo...

CUAL ES LA SOLUCION ?

...

Hector dijo...

Si no te afecta utilizar disparadores, yo utilizaría la primera ... la "elegante" =)

Es la solución más extendida, pero en migraciones de entornos o cargas masivas de datos los disparadores (triggers) suelen ser un quebradero de cabeza. Por lo que me pareció interesante comentar otro sistema, utilizando la secuencia directamente en el insert, en lugar de a través de un disparador.

Espero que te sea de utilidad.

febowill dijo...

Pretty nice post. I just stumbled upon your blog and wanted to say that I have really enjoyed browsing your blog posts. In any case I’ll be subscribing to your feed and I hope you write again soon!

cialis online