Por Alfonso Ricaño Bringas
Los triggers, como hemos visto, son muy útiles a la hora de mantener la integridad de los datos, así como para implantar reglas de negocios del dominio del sistema a la base de datos.
En este artículo plantearé otro uso los triggers de InterBase, utilizando el siguiente ejemplo real.
La creación de un registro histórico de los cambios en una tabla.
Este caso es típico, por ejemplo, si tenemos una lista de artículos y sus precios, y estos precios son actualizados cada mes.
Tal vez queramos que esos precios históricos (los que van siendo actualizados) queden guardados en algún lugar. En ese caso podemos utilizar un trigger que cada vez que se actualicen los precios de un artículo, guarde el precio anterior en otra tabla.
Veamos la estructura de la tabla de artículos y precios:
CREATE TABLE ARTICULOS
( CVEARTICULO VARCHAR(5) NOT NULL,
NOMBREARTICULO VARCHAR(100) NOT NULL,
PRECIO DOUBLE PRECISION DEFAULT 0,
PRIMARY KEY(CVEARTICULO))
Lo primero que tenemos que hacer es crear otra tabla, la cual será la que contendrá los precios históricos de los artículos. Aquí hay que aclarar que la columna Cvearticulo (la clave del artículo) ya no podrá ser la llave primaria, ya que cada artículo podrá estar repetido tantas veces como se actualice su precio.
Por lo tanto tenemos dos opciones:
La primera es crear un campo llave de tipo entero que sea consecutivo, utilizando un generador y un trigger before insert (como se vió en el primer artículo de triggers).
La segunda opción es declarar como llave primaria el campo cvearticulo junto con los campos de fecha y hora en que fue actualizado. Cualquier opción que se tome es buena, en este ejemplo tomaré la primera.
Las columnas (campos) de hora y fecha también deberán crearse en esta tabla de registro de actualizaciones. Por lo tanto, la tabla quedará así:
CREATE TABLE HISTORICO_ARTICULOS(
IDHISTORICO INTEGER NOT NULL,
CVEARTICULO VARCHAR(5),
PRECIO DOUBLE PRECISION DEFAULT 0,
FECHA DATE,
HORA TIME,
PRIMARY KEY(IDHISTORICO))
Tambien nos surge la duda: Deberemos hacer una relación de integridad de llave foránea (foreign key) desde esta tabla a la de artículos? En mi opinión personal, no. Esto es porque un registro histórico debe reflejar lo que pasó en el pasado, y no necesariamente el estado actual de los datos. De todos modos, si así lo deseamos, se puede crear un trigger que elimine el histórico de un artículo antes de que se elimine el artículo, claro, utilizando un trigger Before Delete.
Vamos a crear el generador para el campo llave de la tabla del registro histórico:
CREATE GENERATOR G_IDHISTORICO;
Ahora hay que crear el trigger que tomará los valores del generador anterior y los asignará al campo IDHISTORICO de la tabla HISTORICO_ARTICULOS cada vez que se inserte un nuevo registro:
CREATE TRIGGER HISTORICO_ARTICULOS_BI FOR HISTORICO_ARTICULOS
BEFORE INSERT
AS
BEGIN
NEW.IDHISTORICO = GEN_ID(G_IDHISTORICO,1);
END
Una vez creado esto, procederemos a crear el trigger que se activará cada vez que se actualice el precio, y colocará el precio anterior en la tabla del registro histórico:
CREATE TRIGGER ARTICULOS_BU FOR ARTICULOS
BEFORE UPDATE
AS
BEGIN
IF (OLD.PRECIO<>NEW.PRECIO) THEN
BEGIN
INSERT INTO HISTORICO_ARTICULOS(CVEARTICULO,PRECIO, FECHA,HORA) VALUES(OLD.CVEARTICULO, OLD.PRECIO, CURRENT_DATE, CURRENT_TIME);
END
END
¡Y eso es todo! Bueno, pero vamos por partes, hay que analizar el código:
Primero, nos damos cuenta de que el trigger es de tipo Before Update, lo que significa que se ejecutará antes de actualizar los datos de la tabla artículos.
Ahora, vemos que se utiliza los prefijos OLD. y NEW. para saber si el precio ha sido modificado, porque si se modificó solamente otra columna, no tendrá caso el registrar la modificación en el registro histórico de precios.
Por lo tanto, se comparan los valores de antes y después de la modificación de la columna PRECIO, y si son diferentes, es obvio que se modificó el precio. Si fue modificado, se inserta un registro en la tabla HISTORICO_ARTICULOS.
Vemos que no se lista el campo IDHISTORICO, ya que el valor de este campo es asignado automáticamente por el trigger HISTORICO_ARTICULOS_BI.
Lo único que resta de explicar son las constantes CURRENT_DATE y CURRENT_TIME.
Hay que hacer notar que estas constantes son nuevas en InterBase 6, por lo que si utilizas una versión anterior deberás hacer algo como CAST('TODAY' AS DATE), y se tendrá que modificar los campos de la tabla HISTORICO_ARTICULOS, ya que en versiones anteriores de InterBase solamente existía el tipo de datos Date, el cual incluía los valores de fecha y hora. En conclusión, esta es otra posible aplicación de los triggers, y tiene muchísimas más. Seguiré pronto con este tema, ya que hay mucho que comentar.
10-Abril-2001