Como seguramente sabes, los generadores (también llamados secuencias) están afuera de las transacciones, eso significa que una vez que obtienen su valor éste permanece, sin importar si después la transacción es grabada o es desechada.

Eso está muy bien, así tiene que ser, sin embargo a veces más bien por una cuestión de estética queremos cambiarlos manualmente.

Ejemplo 1. Se agregaron y se borraron filas a una tabla

GENERADOR1

(haciendo click en la imagen la verás más grande)

Aquí hemos realizado una consulta a la tabla de BANCOS y esto fue lo que obtuvimos. Ahora, queremos agregar una nueva fila. Supuestamente su identificador debería ser 17 pero como a esta tabla se le estuvieron agregando y borrando varias filas durante estos días cuando insertamos una nueva fila esto es lo que obtenemos:

GENERADOR2

(haciendo click en la imagen la verás más grande)

El identificador del Banco no es 17 sino 21, ¿por qué? porque cada vez que se insertó una nueva fila el generador fue aumentando su valor y lo mantuvo aunque luego se haya hecho el ROLLBACK o el DELETE de esa fila.

Ejemplo 2. Se borraron todas las filas de una tabla

DELETE FROM CONCEPTOS

Después de escribir este comando y su correspondiente COMMIT todas las filas de la tabla de CONCEPTOS fueron eliminadas. Después, al insertar un nuevo concepto esto es lo que obtenemos:

GENERADOR3

(haciendo click en la imagen la verás más grande)

 ¿Por qué el identificador del concepto es 1.792 siendo que la tabla de CONCEPTOS tiene una sola fila? Nuevamente la respuesta es la misma: el generador o secuencia una vez que obtiene su valor lo retiene. Como anteriormente se habían insertado 1.791 filas, al insertar una nueva fila su identificador (el cual es siempre igual al que tiene el generador en el momento de la inserción) se incrementó en 1.

¿Es posible cambiar manualmente el valor de un generador o secuencia?

Sí, es posible. Para ello se utiliza el comando SET GENERATOR (se puede usar también ALTER SEQUENCE NombreSecuencia RESTART WITH ValorNumérico). Por ejemplo:

SET GENERATOR
   CONCEPTOS_CON_IDENTI_GEN
TO
   0

Aquí, al generador o secuencia (son sinónimos) llamado CONCEPTOS_CON_IDENTI_GEN se le cambió el valor, su nuevo valor es 0 (cero). Desde luego que puedes escribir cualquier valor que quieras: 1, 2, 10, 2540, 3871, etc.

¿Se puede actualizar el valor de todos los generadores de una sola vez?

Sí, con el siguiente stored procedure basado en el que escribió Daniel P. Guimaraes de Tecnobyte Informática, lo conseguirás. La condición para que funcione es que los nombres de los generadores sean:

NombreTabla_NombreColumna_Gen

si usas el programa EMS SQL Manager y creas los generadores automáticamente porque tus identificadores son autoincrementales entonces ya los nombres de los generadores serán los correctos. Si no usas ese programa o si nombras de forma diferente a tus generadores entonces tendrás que hacerles algunos pequeños cambios a esta rutina.

¿Qué hace este stored procedure?

Actualiza los valores de todos los generadores (secuencias) basándose en el mayor valor guardado actualmente en la columna asociada al generador. La versión del Firebird debe ser 2.0 ó posterior.

SET TERM ^ ;

CREATE PROCEDURE ACTUALIZAR_GENERADORES
AS
   DECLARE VARIABLE lcNombreTabla     VARCHAR(32);
   DECLARE VARIABLE lcNombreColumna   VARCHAR(32);
   DECLARE VARIABLE lcNombreGenerador VARCHAR(32);
   DECLARE VARIABLE lnValorMaximo     BIGINT;
   DECLARE VARIABLE lcComando         VARCHAR(200);
BEGIN

   FOR SELECT
      TRIM(R.RDB$RELATION_NAME),
      TRIM(F.RDB$FIELD_NAME),
      TRIM(G.RDB$GENERATOR_NAME)
   FROM
      RDB$RELATIONS R
   JOIN
      RDB$RELATION_FIELDS F
      ON R.RDB$RELATION_NAME = F.RDB$RELATION_NAME
   JOIN
      RDB$GENERATORS G
         ON G.RDB$GENERATOR_NAME = TRIM(R.RDB$RELATION_NAME) || '_' ||
                                   TRIM(F.RDB$FIELD_NAME) || '_' ||
                                   'GEN'
   INTO
      :lcNombreTabla,
      :lcNombreColumna,
      :lcNombreGenerador
   DO BEGIN
      -- Se halla el valor máximo de la columna asociada al generador
      lcComando = 'SELECT MAX(' || lcNombreColumna || ') FROM ' || lcNombreTabla;
      EXECUTE STATEMENT lcComando INTO lnValorMaximo;
      -- Se actualiza el generador con el valor máximo hallado
      lcComando = 'SET GENERATOR ' || lcNombreGenerador || ' TO ' || COALESCE(lnValorMaximo, 0);
      EXECUTE STATEMENT lcComando;
   END

END^

Después de ejecutar este stored procedure todos los generadores tendrán el valor máximo que tiene la columna asociada a ellos. Este stored procedure es muy útil para no dejar huecos en la numeración de los identificadores. Realmente eso es más bien una cuestión de estética porque al Firebird no le importa si entre un identificador y el siguiente la diferencia es de 1 ó mayor que 1, pero si usamos al identificador como Primary Key lo único que le importa es que no se repitan los números.

Anuncios