Página principal
Artículos y trucos
Catálogo de productos
Ejemplos y descargas
Mis libros
Cursos de formación
Investigación y desarrollo
Libros recomendados
Mis páginas favoritas
Acerca del autor
 
En colaboración con Amazon
 
Intuitive Sight

Más trucos con generadores

Ahora que ya sabe como crear y destruir un generador nos queda conocer cómo podemos obtener el valor actual del generador. ¡Elemental, Watson!, pensará usted. Hasta el alcalde de mi pueblo sabe que existe la función gen_id, que recibe un nombre de generador y un incremento, lo aplica al generador y devuelve el valor del mismo. Casi siempre el generador se utiliza en triggers o procedimientos como los siguientes:

create trigger AsignarCodigoFormaPago for FormasPago
   active before insert position 0 as
begin
   if (new.Codigo is null) then
      new.Codigo = gen_id(FormaPagoGen);
end!

create procedure DameUnNumero returns(Codigo integer) as
begin
   Codigo = gen_id(OtroGenerador, 1);
end!

Ante tanta sabiduría me siento obligado a preguntarle algo: ¿qué valor devuelve gen_id, el que tenía el generador antes del incremento, o el valor posterior? Pues es el valor posterior al incremento el que se retorno. Claro, no esperaba otra cosa de usted...

¿Y cómo puedo obtener el valor actual del generador, pero sin modificarlo? La primera vez que me lo preguntaron, contesté algo que aún me avergüenza recordar:

/* ¡¡¡MUY MALO!!! */
create procedure ValorActual returns(Codigo integer) as
begin
   Codigo = gen_id(OtroGenerador, 1);
   Codigo = gen_id(OtroGenerador, -1);
end!

¿Funcionar? Creo que sí, pero funciona a lo bestia. Con más experiencia sobre mis espaldas, ahora me doy cuenta de que el siguiente procedimiento es más racional:

create procedure ValorActual returns(Codigo integer) as
begin
   Codigo = gen_id(OtroGenerador, 0);
end!

De todos modos sigue existiendo un problema. Supongamos que estamos desarrollando una herramienta de diseño, al estilo de SQL Explorer, o de Marathon. En tal caso, no tendremos a mano un procedimiento como el anterior para cada uno de los generadores de la base de datos. Pero el problema no es grave: gen_id es una función como cualquier otra (aunque causa un efecto secundario), y puede colocarse en una cláusula select. Inmediatamente me viene a la mente la tabla Dual de Oracle: una tabla predefinida que siempre contiene una sóla fila. Si tuviésemos esta tabla en InterBase, nos bastaría ejecutar la siguiente instrucción para conocer el valor actual de un generador:

/* ¡NO FUNCIONA, LA TABLA Dual ES DE ORACLE, NO DE INTERBASE! */
select gen_id(OtroGenerador, 0) from Dual

Bien, no existirá Dual en InterBase, pero sí tenemos la tabla interna del sistema RDB$DATABASE, que hasta donde conozco, siempre tiene una sola fila. Entonces podemos utilizar esta variante:

/* VARIANTE CORRECTA */
select gen_id(OtroGenerador, 0) from RDB$DATABASE

En realidad, SQL Explorer utiliza este otro truco:

/* VARIANTE DE SQL EXPLORER */
select distinct gen_id(OtroGenerador, 0) from RDB$GENERATORS

Por supuesto, el resultado del select anterior ¡siempre tiene una sola fila!.