Cómo crear disparadores (triggers) en postgreSQL

Antes de crear un disparador, comencemos recordando un poco sobre triggers y su función en una base de datos.

Un disparador, también llamado trigger, es un conjunto de sentencias SQL que dependen de un procedimiento almacenado, estos son almacenados dentro de la base de datos.

Los disparadores se asocian con tablas y se utilizan para ejecutarse automáticamente cuando ocurre un evento determinado en nuestra base de datos. A diferencia de los procedimientos almacenados un trigger no puede ser invocado directamente, sin mencionar que los disparadores son utilizados mayormente para mantener la integridad de los datos no para obtener resultados de consultas.

Los disparadores se ejecutan como resultado de la ejecución de una instrucción esta puede ser INSERT, UPDATE o DELETE.

La estructura básica de un trigger es:

CREATE TRIGGER nombre 
{ BEFORE | AFTER } { INSERT | UPDATE | DELETE } 
 ON tabla [ FOR [ EACH ] { ROW | STATEMENT } ]
 EXECUTE PROCEDURE nombre de funcion ( argumentos )

Descripción de la estructura:

  • Se utiliza el CREATE TRIGGER seguido del nombre del disparador que se esta creando.
  • Se utiliza BEFORE o AFTER
    ( BEFORE si se desea que la instrucción ocurra ANTES y AFTER si se desea que ocurra DESPUÉS de cualquier INSERT, UPDATE ó DELETE ).
  • Se utiliza ON seguido del nombre de la tabla donde se aplicará el disparador.
  • A continuación se presentan dos opciones, si el disparador se aplicara una sola vez, o se aplicará a cada una de las tuplas en la tabla.
    Si se aplicará una sola vez se coloca FOR EACH STATEMENT.
    Si se aplicará a todas las tuplas de la tabla se utiliza FOR EACH ROW.
  • Por ultimo EXECUTE PROCEDURE seguido por el nombre la función que ejecutará.

Debemos tener en cuenta que por cada disparador que definamos en una tabla, la base de datos tendrá que ejecutar la función asociada a dicho disparador por lo tanto es importante que el nombre de la función que se ejecutará sea el mismo que el nombre con el que es llamada.

La estructura básica de una función llamada por un trigger es:

 CREATE OR REPLACE
 FUNCTION nombre de funcion()
 RETURNS TRIGGER AS $nombre de funcion$
 DECLARE  
 BEGIN 
        --funciones que llevara acabo el disparador
 RETURN;
 END
$nombre de funcion$ LANGUAGE plpgsql;

Descripción de la estructura:

  • Se utiliza CREATE OR REPLACE al inicio de la función, si realizaste un cambio puedes volver a ejecutar la función sin tener que eliminarla.
  • Se utiliza FUNCTION seguido del nombre de la función que se esta creando.
  • RETURNS TRIGGER AS seguido del nombre del la función $.
  • A continuación se puede hacer uso de DECLARE utilizado para la declaración de variables que mas adelante se utilizaran en la elaboración de la función.
  • Dentro del BEGIN se colocan las instrucciones que se realizaran, es el núcleo de la función, al terminar regresa un valor con RETURN seguido de un END.
  • Para finalizar se coloca $nombre de la funcion$ seguido de LANGUAGE plpgsql.

Dentro del BEGIN, se puede acceder a elementos de la fila que se  esta insertando, eliminando o actualizando utilizando las referencias NEW.column-name y OLD.column-name, donde column-name es el nombre de la columna de la tabla con la que se asocia el disparador.

-NEW: Variable que contiene la nueva fila de la tabla para las operaciones  INSERT/UPDATE en disparadores del tipo row-level.

-OLD: Variable que contiene la antigua fila de la tabla para las operaciones UPDATE/DELETE en disparadores del tipo row-level.

Ya que conocemos todos los elementos que integran un disparador, a continuación te presento un ejemplo.

Ejemplo: Verifica existencias de producto al hacer la compra

CREATE TRIGGER verificarExistencias
 BEFORE INSERT ON VENTAS.T_DETALLE_VENTAS
 FOR EACH ROW
 EXECUTE PROCEDURE verificarExistencias();
 CREATE OR REPLACE
 FUNCTION verificaExistencias()
 RETURNS TRIGGER AS $verificaExistencias$
 DECLARE  cant int8; id_Socio int8; cant_Detalle int8;
 BEGIN id_Socio = NEW.id_Producto;
       cant_Detalle = NEW.cantidad;
       cant = cantidad_Producto
 FROM VENTAS.T_PRODUCTOS
 WHERE VENTAS.T_PRODUCTOS.id_Producto = id_Socio;
 IF (cant < cant_Detalle) 
    THEN raise notice 'No hay suficiente producto';
    ROLLBACK;
    return null;
 END IF;
 RETURN NEW;
 END
$verificarExistencias$ LANGUAGE plpgsql;