CREATE TRIGGER

CREATE TRIGGER — define un nuevo disparador (trigger)

Synopsis

CREATE [ OR REPLACE ] [ CONSTRAINT ] TRIGGER nombre { BEFORE | AFTER | INSTEAD OF } { evento [ OR ... ] }
    ON nombre_tabla
    [ FROM nombre_tabla_referenciada ]
    [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ]
    [ REFERENCING { { OLD | NEW } TABLE [ AS ] nombre_relación_transición } [ ... ] ]
    [ FOR [ EACH ] { ROW | STATEMENT } ]
    [ WHEN ( condición ) ]
    EXECUTE { FUNCTION | PROCEDURE } nombre_función ( argumentos )

donde evento puede ser uno de:

    INSERT
    UPDATE [ OF nombre_columna [, ... ] ]
    DELETE
    TRUNCATE

Descripción

CREATE TRIGGER crea un nuevo disparador. CREATE OR REPLACE TRIGGER creará un nuevo disparador o reemplazará un disparador existente. El disparador se asociará con la tabla, vista o tabla foránea especificada y ejecutará la función especificada nombre_función cuando se realicen ciertas operaciones en esa tabla.

Para reemplazar la definición actual de un disparador existente, usa CREATE OR REPLACE TRIGGER, especificando el nombre del disparador existente y su tabla asociada. Todas las demás propiedades se reemplazan.

Se puede especificar que el disparador se ejecute antes de intentar la operación en una fila (antes de comprobar las restricciones y de intentar la operación INSERT, UPDATE o DELETE); o después de completar la operación (después de comprobar las restricciones y de completar la operación INSERT, UPDATE o DELETE); o en lugar de la operación (en el caso de inserciones, actualizaciones o eliminaciones en una vista). Si el disparador se ejecuta antes o en lugar del evento, el disparador puede omitir la operación para la fila actual, o cambiar la fila que se está insertando (solo para operaciones INSERT y UPDATE). Si el disparador se ejecuta después del evento, todos los cambios, incluidos los efectos de otros disparadores, son visibles para el disparador.

Un disparador marcado como FOR EACH ROW se invoca una vez por cada fila que modifica la operación. Por ejemplo, un comando DELETE que afecta a 10 filas provocará que los disparadores ON DELETE de la relación destino se ejecuten 10 veces distintas, una por cada fila eliminada. En cambio, un disparador marcado como FOR EACH STATEMENT solo se ejecuta una vez para cualquier operación dada, independientemente de cuántas filas modifique (en particular, una operación que modifique cero filas seguirá dando como resultado la ejecución de los disparadores FOR EACH STATEMENT que correspondan).

Los disparadores que se especifican para ejecutarse INSTEAD OF el evento del disparador deben estar marcados como FOR EACH ROW, y solo se pueden definir en vistas. Los disparadores BEFORE y AFTER en una vista deben estar marcados como FOR EACH STATEMENT.

Además, los disparadores se pueden definir para ejecutarse en TRUNCATE, aunque solo FOR EACH STATEMENT.

La siguiente tabla resume qué tipos de disparadores se pueden utilizar en tablas, vistas y tablas foráneas:

CuándoEventoA nivel de filaA nivel de sentencia
BEFOREINSERT/UPDATE/DELETETablas y tablas foráneasTablas, vistas y tablas foráneas
TRUNCATETablas y tablas foráneas
AFTERINSERT/UPDATE/DELETETablas y tablas foráneasTablas, vistas y tablas foráneas
TRUNCATETablas y tablas foráneas
INSTEAD OFINSERT/UPDATE/DELETEVistas
TRUNCATE

Además, la definición de un disparador puede especificar una condición booleana WHEN, que se evaluará para ver si el disparador debe ejecutarse. En los disparadores a nivel de fila, la condición WHEN puede examinar los valores antiguos y/o nuevos de las columnas de la fila. Los disparadores a nivel de sentencia también pueden tener condiciones WHEN, aunque esta característica no es tan útil para ellos, ya que la condición no puede hacer referencia a ningún valor de la tabla.

Si se definen varios disparadores del mismo tipo para el mismo evento, se ejecutarán en orden alfabético por nombre.

Cuando se especifica la opción CONSTRAINT, este comando crea un disparador de restricción (constraint trigger). Es lo mismo que un disparador normal, excepto que el momento de ejecución del disparador se puede ajustar usando SET CONSTRAINTS. Los disparadores de restricción deben ser disparadores AFTER ROW en tablas comunes (no tablas foráneas). Pueden ejecutarse al final de la sentencia que causa el evento disparador, o al final de la transacción contenedora; en este último caso se dice que están diferidos. La ejecución de un disparador diferido pendiente también se puede forzar para que ocurra inmediatamente usando SET CONSTRAINTS. Se espera que los disparadores de restricción generen una excepción cuando se violen las restricciones que implementan.

La opción REFERENCING habilita la recopilación de relaciones de transición, que son conjuntos de filas que incluyen todas las filas insertadas, eliminadas o modificadas por la sentencia SQL actual. Esta característica permite al disparador ver una vista global de lo que hizo la sentencia, no solo una fila a la vez. Esta opción solo se permite para disparadores AFTER en tablas comunes (no tablas foráneas). El disparador no debe ser un disparador de restricción. Además, si el disparador es un disparador UPDATE, no debe especificar una lista de nombre_columna cuando use esta opción. OLD TABLE solo se puede especificar una vez, y solo para un disparador que se pueda ejecutar en UPDATE o DELETE; crea una relación de transición que contiene las imágenes previas (before-images) de todas las filas actualizadas o eliminadas por la sentencia. Del mismo modo, NEW TABLE solo se puede especificar una vez, y solo para un disparador que se pueda ejecutar en UPDATE o INSERT; crea una relación de transición que contiene las imágenes posteriores (after-images) de todas las filas actualizadas o insertadas por la sentencia.

SELECT no modifica ninguna fila, por lo que no puedes crear disparadores SELECT. Las reglas (rules) y las vistas pueden proporcionar soluciones viables a los problemas que parecen necesitar disparadores de tipo SELECT.

Consulta Chapter 37 para obtener más información sobre disparadores.

Parámetros

nombre

El nombre que se le dará al nuevo disparador. Debe ser distinto de cualquier otro disparador para la misma tabla. El nombre no puede ser calificado por esquema; el disparador hereda el esquema de su tabla. Para un disparador de restricción, este es también el nombre que se debe utilizar al modificar el comportamiento del disparador mediante SET CONSTRAINTS.

BEFORE
AFTER
INSTEAD OF

Determina si la función se llama antes, después o en lugar del evento. Un disparador de restricción solo se puede especificar como AFTER.

evento

Uno de los valores INSERT, UPDATE, DELETE o TRUNCATE; esto especifica el evento que ejecutará el disparador. Se pueden especificar varios eventos utilizando OR, excepto cuando se solicitan relaciones de transición.

Para eventos de tipo UPDATE, es posible especificar una lista de columnas utilizando esta sintaxis:

UPDATE OF nombre_columna1 [, nombre_columna2 ... ]

El disparador solo se ejecutará si al menos una de las columnas enumeradas se menciona como destino del comando UPDATE o si una de las columnas de la lista es una columna generada que depende de una columna que es destino del comando UPDATE.

Los eventos INSTEAD OF UPDATE no permiten una lista de columnas. Tampoco se puede especificar una lista de columnas cuando se solicitan relaciones de transición.

nombre_tabla

El nombre (opcionalmente calificado por esquema) de la tabla, vista o tabla foránea para la cual se define el disparador.

nombre_tabla_referenciada

El nombre (posiblemente calificado por esquema) de otra tabla referenciada por la restricción. Esta opción se utiliza para restricciones de clave foránea y no se recomienda para uso general. Solo se puede especificar para disparadores de restricción.

DEFERRABLE
NOT DEFERRABLE
INITIALLY IMMEDIATE
INITIALLY DEFERRED

El momento de ejecución por defecto del disparador. Consulta la documentación de CREATE TABLE para obtener detalles de estas opciones de restricción. Esto solo se puede especificar para disparadores de restricción.

REFERENCING

Esta palabra clave precede inmediatamente a la declaración de uno o dos nombres de relación que proporcionan acceso a las relaciones de transición de la sentencia que causó la ejecución.

OLD TABLE
NEW TABLE

Esta cláusula indica si el nombre de relación siguiente es para la relación de transición de imagen previa o para la relación de transición de imagen posterior.

nombre_relación_transición

El nombre (sin calificar) que se utilizará dentro del disparador para esta relación de transición.

FOR EACH ROW
FOR EACH STATEMENT

Especifica si la función del disparador debe ejecutarse una vez por cada fila afectada por el evento, o solo una vez por sentencia SQL. Si no se especifica ninguno, el valor por defecto es FOR EACH STATEMENT. Los disparadores de restricción solo se pueden especificar como FOR EACH ROW.

condición

Una expresión booleana que determina si la función del disparador se ejecutará realmente. Si se especifica WHEN, la función solo se llamará si la condición devuelve true. En los disparadores FOR EACH ROW, la condición WHEN puede referirse a columnas de los valores de fila antiguos y/o nuevos escribiendo OLD.nombre_columna o NEW.nombre_columna, respectivamente. Por supuesto, los disparadores INSERT no pueden hacer referencia a OLD y los disparadores DELETE no pueden hacer referencia a NEW.

Los disparadores de tipo INSTEAD OF no admiten condiciones WHEN.

Actualmente, las expresiones WHEN no pueden contener subconsultas.

Ten en cuenta que para los disparadores de restricción, la evaluación de la condición WHEN no se difiere, sino que ocurre inmediatamente después de realizar la operación de actualización de la fila. Si la condición no evalúa a verdadero, el disparador no se encola para su ejecución diferida.

nombre_función

Una función proporcionada por el usuario que se declara como una función sin argumentos y que devuelve el tipo trigger, la cual se ejecuta cuando el disparador se activa.

En la sintaxis de CREATE TRIGGER, las palabras clave FUNCTION y PROCEDURE son equivalentes, pero la función referenciada debe ser en cualquier caso una función, no un procedimiento. El uso de la palabra clave PROCEDURE aquí es histórico y está obsoleto.

argumentos

Una lista opcional de argumentos separados por comas que se proporcionarán a la función cuando se ejecute el disparador. Los argumentos son constantes de cadena literal. Aquí también se pueden escribir nombres simples y constantes numéricas, pero todos se convertirán en cadenas de texto. Consulta la descripción del lenguaje de implementación de la función del disparador para saber cómo se puede acceder a estos argumentos dentro de la función; puede ser diferente de los argumentos de funciones normales.

Notas

Para crear o reemplazar un disparador en una tabla, el usuario debe tener el privilegio TRIGGER en la tabla. El usuario también debe tener el privilegio EXECUTE en la función del disparador.

Usa DROP TRIGGER para eliminar un disparador.

La creación de un disparador a nivel de fila en una tabla particionada provocará la creación de un disparador clon idéntico en cada una de sus particiones existentes; y cualquier partición que se cree o acople más tarde también tendrá un disparador idéntico. Si ya existe un disparador con nombre en conflicto en una partición hija, se produce un error a menos que se utilice CREATE OR REPLACE TRIGGER, en cuyo caso ese disparador se reemplaza con un disparador clon. Cuando una partición se desacopla de su padre, sus disparadores clon se eliminan.

Un disparador específico de columna (uno definido mediante la sintaxis UPDATE OF nombre_columna) se ejecutará cuando cualquiera de sus columnas figuren como destinos en la lista SET del comando UPDATE. Es posible que el valor de una columna cambie incluso cuando el disparador no se ejecute, ya que no se consideran los cambios realizados en el contenido de la fila por los disparadores BEFORE UPDATE. Por el contrario, un comando como UPDATE ... SET x = x ... ejecutará un disparador en la columna x, aunque el valor de la columna no haya cambiado.

En un disparador BEFORE, la condición WHEN se evalúa justo antes de que la función se ejecute o se fuera a ejecutar, por lo que usar WHEN no es materialmente diferente de probar la misma condición al comienzo de la función del disparador. Ten en cuenta en particular que la fila NEW vista por la condición es el valor actual, posiblemente modificado por disparadores anteriores. Además, no se permite que la condición WHEN de un disparador BEFORE examine las columnas del sistema de la fila NEW (como ctid), porque estas aún no se habrán establecido.

En un disparador AFTER, la condición WHEN se evalúa justo después de que ocurra la actualización de la fila y determina si se encola un evento para ejecutar el disparador al final de la sentencia. Por lo tanto, cuando la condición WHEN de un disparador AFTER no devuelve true, no es necesario encolar un evento ni volver a obtener la fila al final de la sentencia. Esto puede resultar en aceleraciones significativas en sentencias que modifican muchas filas, si el disparador solo necesita ejecutarse para unas pocas filas.

En algunos casos es posible que un solo comando SQL ejecute más de un tipo de disparador. Por ejemplo, un INSERT con una cláusula ON CONFLICT DO UPDATE puede causar operaciones tanto de inserción como de actualización, por lo que ejecutará ambos tipos de disparadores según sea necesario. Las relaciones de transición suministradas a los disparadores son específicas de su tipo de evento; por lo tanto, un disparador INSERT solo verá las filas insertadas, mientras que un disparador UPDATE solo verá las filas actualizadas.

Las actualizaciones o eliminaciones de filas causadas por acciones de cumplimiento de claves foráneas, como ON UPDATE CASCADE o ON DELETE SET NULL, se tratan como parte del comando SQL que las causó (ten en cuenta que tales acciones nunca se difieren). Se ejecutarán los disparadores correspondientes en la tabla afectada, de modo que esto proporciona otra forma en la que un comando SQL podría ejecutar disparadores que no coinciden directamente con su tipo. En casos sencillos, los disparadores que solicitan relaciones de transición verán todos los cambios causados en su tabla por un solo comando SQL original como una única relación de transición. Sin embargo, hay casos en los que la presencia de un disparador AFTER ROW que solicita relaciones de transición provocará que las acciones de cumplimiento de clave foránea desencadenadas por un único comando SQL se dividan en varios pasos, cada uno con sus propias relaciones de transición. En tales casos, los disparadores a nivel de sentencia que estén presentes se ejecutarán una vez por cada creación de un conjunto de relaciones de transición, garantizando que los disparadores vean cada fila afectada en una relación de transición una y solo una vez.

Los disparadores a nivel de sentencia en una vista se ejecutan solo si la acción en la vista es manejada por un disparador INSTEAD OF a nivel de fila. Si la acción es manejada por una regla INSTEAD, entonces cualquier sentencia emitida por la regla se ejecuta en lugar de la sentencia original que nombra la vista, por lo que los disparadores que se ejecutarán serán aquellos en las tablas nombradas en las sentencias de reemplazo. Del mismo modo, si la vista es actualizable automáticamente, entonces la acción se maneja reescribiendo automáticamente la sentencia en una acción en la tabla base de la vista, por lo que los disparadores a nivel de sentencia de la tabla base son los que se ejecutan.

Modificar una tabla particionada o una tabla con hijos heredados ejecuta disparadores a nivel de sentencia asociados a la tabla nombrada explícitamente, pero no disparadores a nivel de sentencia para sus particiones o tablas hijas. En cambio, los disparadores a nivel de fila se ejecutan en las filas de las particiones o tablas hijas afectadas, incluso si no están nombradas explícitamente en la consulta. Si se ha definido un disparador a nivel de sentencia con relaciones de transición nombradas mediante una cláusula REFERENCING, entonces las imágenes previas y posteriores de las filas serán visibles desde todas las particiones o tablas hijas afectadas. En el caso de hijos heredados, las imágenes de las filas incluyen únicamente las columnas presentes en la tabla a la que está asociado el disparador.

Actualmente, los disparadores a nivel de fila con relaciones de transición no se pueden definir en particiones o tablas hijas de herencia. Además, los disparadores en tablas particionadas no pueden ser de tipo INSTEAD OF.

Actualmente, la opción OR REPLACE no es compatible con los disparadores de restricción.

No se recomienda reemplazar un disparador existente dentro de una transacción que ya ha realizado acciones de actualización en la tabla del disparador. Las decisiones de ejecución del disparador, o partes de las decisiones de ejecución que ya se hayan tomado, no se reconsiderarán, por lo que los efectos podrían ser sorprendentes.

Hay algunas funciones de disparador integradas que se pueden utilizar para resolver problemas comunes sin tener que escribir su propio código de disparador; consulta Section 9.29.

Ejemplos

Ejecuta la función check_account_update cada vez que una fila de la tabla accounts esté a punto de actualizarse:

CREATE TRIGGER check_update
    BEFORE UPDATE ON accounts
    FOR EACH ROW
    EXECUTE FUNCTION check_account_update();

Modifica la definición de ese disparador para ejecutar la función únicamente si la columna balance se especifica como destino en el comando UPDATE:

CREATE OR REPLACE TRIGGER check_update
    BEFORE UPDATE OF balance ON accounts
    FOR EACH ROW
    EXECUTE FUNCTION check_account_update();

Esta forma solo ejecuta la función si la columna balance ha cambiado de valor:

CREATE TRIGGER check_update
    BEFORE UPDATE ON accounts
    FOR EACH ROW
    WHEN (OLD.balance IS DISTINCT FROM NEW.balance)
    EXECUTE FUNCTION check_account_update();

Llama a una función para registrar las actualizaciones de accounts, pero solo si algo cambió:

CREATE TRIGGER log_update
    AFTER UPDATE ON accounts
    FOR EACH ROW
    WHEN (OLD.* IS DISTINCT FROM NEW.*)
    EXECUTE FUNCTION log_account_update();

Ejecuta la función view_insert_row para cada fila a fin de insertar filas en las tablas subyacentes de una vista:

CREATE TRIGGER view_insert
    INSTEAD OF INSERT ON my_view
    FOR EACH ROW
    EXECUTE FUNCTION view_insert_row();

Ejecuta la función check_transfer_balances_to_zero para cada sentencia a fin de confirmar que las filas de transfer se compensan para un neto de cero:

CREATE TRIGGER transfer_insert
    AFTER INSERT ON transfer
    REFERENCING NEW TABLE AS inserted
    FOR EACH STATEMENT
    EXECUTE FUNCTION check_transfer_balances_to_zero();

Ejecuta la función check_matching_pairs para cada fila a fin de confirmar que los cambios se realizan en pares coincidentes al mismo tiempo (por la misma sentencia):

CREATE TRIGGER paired_items_update
    AFTER UPDATE ON paired_items
    REFERENCING NEW TABLE AS newtab OLD TABLE AS oldtab
    FOR EACH ROW
    EXECUTE FUNCTION check_matching_pairs();

Section 37.4 contiene un ejemplo completo de una función de disparador escrita en C.

Compatibilidad

La sentencia CREATE TRIGGER en PostgreSQL implementa un subconjunto del estándar SQL. Actualmente faltan las siguientes funcionalidades:

  • Aunque los nombres de las tablas de transición para los disparadores AFTER se especifican utilizando la cláusula REFERENCING de la forma estándar, las variables de fila utilizadas en los disparadores FOR EACH ROW no se pueden especificar en una cláusula REFERENCING. Están disponibles de una manera que depende del lenguaje en el que esté escrita la función del disparador, pero es fija para cualquier lenguaje. Algunos lenguajes se comportan efectivamente como si hubiera una cláusula REFERENCING que contuviera OLD ROW AS OLD NEW ROW AS NEW.

  • El estándar permite que las tablas de transición se utilicen con disparadores UPDATE específicos de columnas, pero entonces el conjunto de filas que debe ser visible en las tablas de transición depende de la lista de columnas del disparador. Esto no está implementado actualmente por PostgreSQL.

  • PostgreSQL solo permite la ejecución de una función definida por el usuario para la acción desencadenada. El estándar permite la ejecución de una serie de otros comandos SQL, como CREATE TABLE, como acción desencadenada. Esta limitación no es difícil de solucionar creando una función definida por el usuario que ejecute los comandos deseados.

SQL especifica que los disparadores múltiples deben ejecutarse en el orden del momento de su creación. PostgreSQL utiliza el orden alfabético de los nombres, lo que se consideró más conveniente.

SQL especifica que los disparadores BEFORE DELETE en las eliminaciones en cascada se ejecutan después de que se complete el DELETE en cascada. El comportamiento de PostgreSQL es que BEFORE DELETE siempre se ejecute antes de la acción de eliminación, incluso una en cascada. Esto se considera más coherente. También hay un comportamiento no estándar si los disparadores BEFORE modifican filas o evitan actualizaciones durante una actualización causada por una acción referencial. Esto puede provocar violaciones de restricciones o datos almacenados que no respeten la restricción referencial.

La capacidad de especificar múltiples acciones para un solo disparador utilizando OR es una extensión de PostgreSQL al estándar SQL.

La capacidad de ejecutar disparadores para TRUNCATE es una extensión de PostgreSQL al estándar SQL, al igual que la capacidad de definir disparadores a nivel de sentencia en vistas.

CREATE CONSTRAINT TRIGGER es una extensión de PostgreSQL al estándar SQL. También lo es la opción OR REPLACE.

Consulte también

ALTER TRIGGER, DROP TRIGGER, CREATE FUNCTION, SET CONSTRAINTS