CodeGym /Cursos /SQL SELF /Tipos de triggers en PostgreSQL: BEFORE, AFTER, INSTEAD O...

Tipos de triggers en PostgreSQL: BEFORE, AFTER, INSTEAD OF

SQL SELF
Nivel 57 , Lección 1
Disponible

Los triggers en PostgreSQL se dividen en tres categorías principales:

  1. BEFORE — se ejecutan antes de la operación principal (por ejemplo, antes de INSERT, UPDATE o DELETE). Puedes usarlos para evitar que se realice la operación o modificar los datos antes de guardarlos.

  2. AFTER — se ejecutan después de que la operación principal ha terminado. Este tipo se usa mucho para logging, crear registros relacionados o hacer cosas que dependen de que la operación haya salido bien.

  3. INSTEAD OF — se ejecutan en vez de la operación real. Solo se usan para vistas. Por ejemplo, si alguien intenta insertar datos en una vista, puedes controlar ese proceso con un trigger INSTEAD OF.

Trigger BEFORE

Los triggers BEFORE se lanzan antes de que PostgreSQL haga la operación principal. Son útiles si quieres chequear o cambiar datos justo antes de guardarlos. Imagínate que es como revisar tu equipaje antes de subir al avión: si algo no cuadra, puedes cambiarlo o incluso bloquearlo.

Vamos con un ejemplo de validación de datos antes de insertar. Supón que tienes una tabla students donde guardas info sobre estudiantes. Queremos asegurarnos de que la edad del estudiante no pase de 100 años (poco probable, pero bueno).

Creamos la tabla:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    age INT NOT NULL
);

Creamos la función para el trigger:

CREATE OR REPLACE FUNCTION validate_age()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.age > 100 THEN
        RAISE EXCEPTION '¡La edad del estudiante no puede ser mayor de 100 años!';
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Creamos el trigger:

CREATE TRIGGER before_insert_students
BEFORE INSERT ON students
FOR EACH ROW
EXECUTE FUNCTION validate_age();

Ahora, si intentas meter un estudiante con más de 100 años, PostgreSQL te va a dar un error:

INSERT INTO students (name, age) VALUES ('Ivan Ivanov', 120);
-- Error: ¡La edad del estudiante no puede ser mayor de 100 años!

¡Así de fácil la validación!

Trigger AFTER

Los triggers AFTER se lanzan después de que la operación principal ha terminado bien. Son útiles para hacer cosas que dependen del resultado de la operación. Por ejemplo, logging o crear registros relacionados.

Escenario: tenemos la tabla students y queremos guardar todos los cambios en una tabla de logs aparte.

Creamos la tabla para los logs:

CREATE TABLE students_log (
    id SERIAL PRIMARY KEY,
    student_id INT,
    operation TEXT,
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Creamos la función para el trigger:

CREATE OR REPLACE FUNCTION log_student_changes()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO students_log (student_id, operation)
    VALUES (NEW.id, TG_OP);  -- TG_OP contiene el tipo de operación: INSERT, UPDATE o DELETE
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Creamos el trigger:

CREATE TRIGGER after_insert_students
AFTER INSERT ON students
FOR EACH ROW
EXECUTE FUNCTION log_student_changes();

Ahora, cuando añades un nuevo estudiante, PostgreSQL mete la operación en el log automáticamente:

INSERT INTO students (name, age) VALUES ('Anna Ling', 22);

SELECT * FROM students_log;
-- Resultado:
-- id | student_id | operation |        timestamp
--  1 |          1 | INSERT    | 2023-11-15 12:00:00

Trigger INSTEAD OF

Los triggers INSTEAD OF saltan en vez de hacer la operación. Es el único tipo de trigger que puedes usar con vistas (views). Te dan flexibilidad para manejar operaciones que no se pueden hacer directamente sobre la vista.

Escenario: tenemos dos tablas courses y teachers. Vamos a crear una vista que las junte y escribir un trigger para manejar inserts a través de esa vista.

Creamos las tablas:

CREATE TABLE courses (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    teacher_id INT NOT NULL
);

CREATE TABLE teachers (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

Creamos la vista:

CREATE VIEW course_details AS
SELECT 
    courses.id AS course_id,
    courses.name AS course_name,
    teachers.name AS teacher_name
FROM courses
JOIN teachers ON courses.teacher_id = teachers.id;

Problema: no puedes simplemente insertar datos en la vista, porque junta datos de dos tablas. Solución: usamos un trigger INSTEAD OF.

Creamos la función para el trigger:

CREATE OR REPLACE FUNCTION insert_course_details()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO teachers (name) VALUES (NEW.teacher_name) RETURNING id INTO NEW.teacher_id;
    INSERT INTO courses (name, teacher_id) VALUES (NEW.course_name, NEW.teacher_id);
    RETURN NULL;  -- En la vista no se guardan datos
END;
$$ LANGUAGE plpgsql;

Creamos el trigger:

CREATE TRIGGER instead_of_insert_course_details
INSTEAD OF INSERT ON course_details
FOR EACH ROW
EXECUTE FUNCTION insert_course_details();

Ahora puedes insertar datos directamente en la vista:

INSERT INTO course_details (course_name, teacher_name)
VALUES ('Matemáticas', 'Alex Ming');

SELECT * FROM courses;
-- Resultado:
-- id | name        | teacher_id
--  1 | Matemáticas | 1

SELECT * FROM teachers;
-- Resultado:
-- id | name
--  1 | Alex Ming

Comparación de tipos de triggers

Tipo de trigger Cuándo se ejecuta Uso principal
BEFORE Antes de la operación Validación, preparación de datos
AFTER Después de terminar con éxito Logging, actualización de datos relacionados
INSTEAD OF En vez de la operación Manejo de operaciones en vistas

Particularidades y limitaciones

Los triggers BEFORE pueden cambiar los datos antes de la operación. Por ejemplo, puedes poner los nombres en mayúsculas automáticamente.

Los triggers AFTER no pueden cambiar los datos, porque la operación ya terminó. Son solo para acciones posteriores.

Los triggers INSTEAD OF solo se usan en vistas. Te dejan implementar lógica compleja de inserción/modificación de datos en varias tablas relacionadas.

¡Y eso es todo por hoy! Si BEFORE, AFTER e INSTEAD OF te parecen complicados, tranqui. Lo importante es recordar el principio básico y los escenarios de uso. Prueba a hacer algunos ejemplos tú mismo para afianzar el tema.

2
Tarea
SQL SELF, nivel 57, lección 1
Bloqueada
Creación de un trigger `BEFORE` para validar datos
Creación de un trigger `BEFORE` para validar datos
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION