Creación y uso de funciones y triggers en bases de datos SQL
Resumen
¿Cómo crear funciones en PL/pgSQL?
Dominar las funciones en PL/pgSQL es fundamental para maximizar el potencial de tus bases de datos PostgreSQL. En esta guía, nos enfocaremos en la estructura básica de las funciones y cómo integrarlas utilizando el lenguaje de procedimiento PL/pgSQL.
¿Cuál es la estructura básica de una función?
Para crear funciones de manera eficiente, es crucial memorizar su estructura. A continuación, te muestro cómo crear una función paso a paso:
Definición de la función: Inicia con CREATE FUNCTION <nombre_función> <parámetros>.
Tipo de retorno: Declara lo que tu función retornará, como un entero (RETURNS integer).
Lenguaje utilizado: Especifica que la función usará PL/pgSQL al escribir LANGUAGE plpgsql.
Cuerpo de la función: Entre BEGIN y END, define la lógica de tu función.
Ejemplo de función para contar registros:
CREATEFUNCTION cuenta_total_peliculas()RETURNSintegerAS $$
BEGINRETURN(SELECTCOUNT(*)FROM peliculas);END;$$ LANGUAGE plpgsql;
Esta función regresa el conteo total de películas en nuestra tabla de forma directa y sencilla.
¿Cómo ejecutar una función en PostgreSQL?
Para ejecutar y probar la función que has creado, simplemente utiliza un comando SELECT:
SELECT cuenta_total_peliculas();
Este comando te mostrará el total de películas almacenadas en tu base de datos.
¿Qué son los triggers y cómo funcionan?
Los triggers son una poderosa característica de PostgreSQL, diseñada para ejecutar automáticamente acciones específicas cuando ocurren eventos en la base de datos, como inserciones, actualizaciones o eliminaciones.
¿Cómo crear un trigger asociado a una función?
Para crear funciones que involucren triggers, sigue estos pasos:
Función de trigger: Crea una función específica que ejecutará acciones al producirse el evento.
Definición del trigger: Vincula la función a una tabla y especifica cuándo se debe ejecutar.
Este ejemplo toma una inserción en tabla_a y la duplica en tabla_b.
¿Cómo asociar un trigger a una tabla?
Una vez que hayas creado la función de trigger, asóciala a una tabla con el siguiente comando:
CREATETRIGGER duplicado_antes_insert
BEFORE INSERTON tabla_a
FOR EACH ROWEXECUTEFUNCTION duplica_registro();
Este código indica que antes de cualquier inserción en tabla_a, el trigger ejecutará la función duplica_registro.
¿Qué aplicaciones prácticas tienen los triggers?
Los triggers permiten realizar acciones automáticas, mantener la consistencia de los datos y actualizar estadísticas o registros de auditoría inmediatamente después de los cambios en las tablas.
Ya sea para sincronizar tablas o mantener cálculos actualizados, los triggers pueden facilitar un flujo de trabajo más eficiente y, en conjunto con PL/pgSQL, ofrecen un control avanzado sobre las operaciones de la base de datos.
¡Sigue explorando estas potentes herramientas y amplía tus habilidades en bases de datos PostgreSQL! Mantente siempre curioso y sigue aprendiendo.
Está buena la explicación, sin embargo me parece que hubiera quedado mucho mejor si se usara un ejemplo del mundo real para nombrar los atributos, tablas y procedimientos/funciones en lugar de letras aleatorias del abecedario ('aaa', 'bbb' o 'efghi').
--CreandoTablaMasterCREATETABLEpublic.tabla_master( nombre_master character varying, apellido_master character varying,CONSTRAINT tabla_master_pkey PRIMARYKEY(nombre_master));--CreandoTablaRéplica
CREATETABLEpublic.tabla_replica( nombre_replica character varying, apellido_replica character varying,CONSTRAINT tabla_replica_pkey PRIMARYKEY(nombre_replica));--CreandoFunctionCREATEORREPLACEFUNCTIONduplicate_records()RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGININSERTINTOtabla_replica(nombre_replica, apellido_replica)VALUES(NEW.nombre_master,NEW.apellido_master);RETURNNEW;END$$;--CreandoTriggerCREATETRIGGER duplicate_master_to_replica
BEFOREINSERTON tabla_master
FOREACHROWEXECUTEPROCEDUREduplicate_records();--Haciendo prueba de insert
INSERTINTOtabla_master(nombre_master, apellido_master)VALUES('Juanito','Alimaña');--Validando que los datos esten en ambas tablas
SELECT*FROMpublic.tabla_master;SELECT*FROMpublic.tabla_replica;```
Me agrada mucho como explica todo al detalle; convirtiendo temas un poco enredados a algo más fácil de digerir, como en el curso de fundamentos de bases de datos.
Recuerda que las funciones también son procedures PERO retornan un valor. El profesor hace uso de la sentencia EXECUTE PROCEDURE dado a que es la forma en como Postgres permite definir triggers que llaman funciones.
CREATEORREPLACEFUNCTION count_total_movies()RETURNSintLANGUAGE plpgsql
AS $$
BEGINRETURNCOUNT(*)FROM peliculas;END$$;SELECT count_total_movies();
duplicar registros
-- al haber un insert en un tabla duplica ese registro en otra tablaCREATEORREPLACEFUNCTION duplicate_records()RETURNStriggerLANGUAGE plpgsql
AS $$
BEGIN-- NEW es el registro que se acaba de hacer insertINSERTINTO aaab(bbba, ccca)VALUES(NEW.bbb, NEW.ccc);RETURN NEW;END$$;-- creando el triggerCREATETRIGGER aaa_changes
BEFORE INSERTON aaa
FOR EACH ROWEXECUTEPROCEDURE duplicate_records();-- insertando valores para probar el triggerINSERTINTO aaa(bbb, ccc)VALUES('abcde','efghi');
Me parece fantástico como por medio de triggers y funciones podemos automatizar un backup de información de una tabla principal, será interesante ver las diferentes aplicaciones a las cuales podemos llegar al finalizar este curso. Gracias Israel!
Un detalle sobre los triggers a considerar es que estos pueden llegar a ser un cuello de botella cuando se utilizan en tablas altamente transaccionales y con gran cantidad de volumen de información. Si puedes omitir el uso de un trigger, hazlo. Cámbialo por un stored procedure que pueda ser llamado desde un aplicativo o proceso batch. Si forzosamente debes utilizar un trigger, considera el volumen y transaccionalidad de la tabla para evitar problemas en presente o futuro :)
En PL/pgSQL, los conceptos de conteo, registro y triggers son fundamentales para automatizar y optimizar la gestión de datos en una base de datos. A continuación, exploramos cada uno con ejemplos prácticos:
1. Conteo en PL/pgSQL
El conteo se utiliza para obtener el número de registros en una tabla o como resultado de una consulta específica.
Ejemplo 1: Conteo básico en un procedimiento
Un procedimiento que devuelve la cantidad de usuarios en una tabla:
CREATE PROCEDURE contar_usuarios()
LANGUAGE plpgsql
AS $$
DECLARE
total_usuarios INT;
BEGIN
SELECT COUNT(*) INTO total_usuarios FROM usuarios;
RAISE NOTICE 'Total de usuarios: %', total_usuarios;
END;
$$;
Uso:
CALL contar_usuarios();
Ejemplo 2: Conteo condicional
Un procedimiento que cuenta usuarios por un rango de edad:
CREATE PROCEDURE contar_usuarios_por_edad(edad_min INT, edad_max INT)
LANGUAGE plpgsql
AS $$
DECLARE
total INT;
BEGIN
SELECT COUNT(*) INTO total
FROM usuarios
WHERE edad BETWEEN edad_min AND edad_max;
RAISE NOTICE 'Usuarios entre % y % años: %', edad_min, edad_max, total;
END;
$$;
Uso:
CALL contar_usuarios_por_edad(18, 30);
2. Registro en PL/pgSQL
Registrar eventos, cambios o errores en tablas de auditoría es una práctica común en bases de datos.
Ejemplo: Procedimiento de registro
Este procedimiento registra operaciones realizadas por los usuarios en una tabla de auditoría.
CREATE TABLE auditoria (
id SERIAL PRIMARY KEY,
usuario TEXT,
operacion TEXT,
fecha TIMESTAMP DEFAULT NOW()
);
CREATE PROCEDURE registrar_operacion(usuario TEXT, operacion TEXT)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO auditoria (usuario, operacion) VALUES (usuario, operacion);
RAISE NOTICE 'Operación registrada: Usuario % realizó %', usuario, operacion;
END;
$$;
Uso:
CALL registrar_operacion('admin', 'inserción de datos');
3. Triggers en PL/pgSQL
Los triggers (disparadores) son funciones que se ejecutan automáticamente en respuesta a eventos (INSERT, UPDATE, DELETE) en una tabla.
Sintaxis básica para un trigger
Un trigger necesita una función asociada:
Crear la función del trigger.
Asociar la función al evento mediante CREATE TRIGGER.
Ejemplo 1: Trigger de registro de cambios
Registrar automáticamente cada actualización de una tabla usuarios en la tabla auditoria.
Crear la función del trigger:
CREATE OR REPLACE FUNCTION registrar_cambio()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO auditoria (usuario, operacion)
VALUES (OLD.nombre, 'Actualización');
RETURN NEW;
END;
$$;
Asociar el trigger:
CREATE TRIGGER trigger_registro_cambios
AFTER UPDATE ON usuarios
FOR EACH ROW
EXECUTE FUNCTION registrar_cambio();
Efecto: Cada vez que se actualice un registro en usuarios, se añadirá una entrada en auditoria.
Ejemplo 2: Evitar bajas de usuarios con permisos especiales
Prevenir la eliminación de usuarios con el rol admin.
Crear la función del trigger:
CREATE OR REPLACE FUNCTION evitar_eliminar_admin()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
IF OLD.rol = 'admin' THEN
RAISE EXCEPTION 'No se puede eliminar un administrador.';
END IF;
RETURN OLD;
END;
$$;
Asociar el trigger:
CREATE TRIGGER trigger_prevenir_eliminacion
BEFORE DELETE ON usuarios
FOR EACH ROW
EXECUTE FUNCTION evitar_eliminar_admin();
Ejemplo 3: Actualización automática de conteos
Actualizar el conteo total de usuarios activos en una tabla estadisticas tras cada inserción en la tabla usuarios.
Tabla de estadísticas:
CREATE TABLE estadisticas (
id SERIAL PRIMARY KEY,
total_usuarios INT DEFAULT 0
);
Crear la función del trigger:
CREATE OR REPLACE FUNCTION actualizar_conteo()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE estadisticas
SET total_usuarios = total_usuarios + 1
WHERE id = 1;
RETURN NEW;
END;
$$;
Asociar el trigger:
CREATE TRIGGER trigger_actualizar_conteo
AFTER INSERT ON usuarios
FOR EACH ROW
EXECUTE FUNCTION actualizar_conteo();
Efecto: Cada vez que se agregue un usuario, se incrementará automáticamente el conteo en estadisticas.
Ventajas del uso de Triggers en PL/pgSQL
Automatización: Ejecución de procesos automáticos ante eventos en la base de datos.
Integridad: Garantizan consistencia en los datos.
Auditoría: Facilitan el registro de cambios en las tablas.
Reducción de lógica en la aplicación: Centralizan las reglas de negocio en la base de datos.
PL/pgSQL ofrece herramientas poderosas como triggers, funciones y procedimientos para manejar conteos, auditoría y automatización de tareas, optimizando así el flujo de datos y mejorando la confiabilidad del sistema.
No me queda claro lo que significa NEW en esta sentencia:
CREATEORREPLACEFUNCTIONduplicate_records()RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGININSERTINTOtabla_replica(nombre_replica, apellido_replica)VALUES(NEW.nombre_master,NEW.apellido_master);RETURNNEW;END$$;
Intuitivamente entiendo lo que hace pero nop me queda del todo claro y su uso. Gracias!
NEW es una variable especial que se define a la hora de ejecutar triggers. En este caso, la variable NEW se refiere al registro a insertar proveniente de la tabla aaa. Es decir, es una referencia al record que se insertará e iniciará la ejecución del trigger.
Si es algo complicado entender la implementación del trigger con la función con los "aaa" y "bbb", por lo que hice cambios en mi código para poder entenderlo mejor, así quedó:
--Se crea una función para que a la hora de ingresar datos a la tabla B, se ejecute un trigger
CREATEORREPLACEFUNCTIONduplicate_records()RETURNSTRIGGERLANGUAGE plpgsql
AS $$
BEGININSERTINTOb_tabla(colum_1)VALUES(NEW.colum_1);RETURNNEW;-- tener cuidado con los RETURNS y los RETURNEND$$;--Creamos el TRIGGER que ejecutará la función de arriba, que agregará los datos que se registren en la tabla B, a la tabla ACREATETRIGGER duplicate_records_changes
BEFOREINSERTON a_tabla
FOREACHROWEXECUTEPROCEDUREduplicate_records()--Se insertan datos para comprobar
INSERTINTOa_tabla(colum_1)VALUES('Chris');
Basicamente lo que se hace es que cada vez que se inserte un registro en la tabla "aaa", el Trigger haga que acutomáticamente se inserte ese mismo registro en la tabla "aaab", básicamente es automatizar un proceso
CREATEORREPLACEFUNCTIONduplicate_records()RETURNSTRIGGER--Función tipo trigger.LANGUAGE plpgsql
AS $$
BEGININSERTINTOab_tabla(campo_a, campo_b)--Inserta en los campos campo_a y campo_b de la tabla ab_tabla.VALUES(NEW.campo_b,NEW.campo_c);--Inserta el nuevo valor que tiene el campo_b(a_tabla) en campo_a(ab_tabla).RETURNNEW;--Regresa los campos que tendrá la tabla modificada, en este caso los nuevos.END$$;CREATETRIGGER a_tabla_changes --Trigger para inserciones en a_tabla.BEFOREINSERT--Realiza el llamado antes de hacer el insert.ON a_tabla --Tabla que al cambiar se llamará el trigger.FOREACHROW--Para cada fila define que ejecutar.EXECUTEPROCEDUREduplicate_records();--Ejecuta la función tipo trigger para copiar los valores a la tabla ab_tabla.INSERTINTOa_tabla(campo_b, campo_c)VALUES('valA','valB');SELECT*FROM a_tabla, ab_tabla;
Se estan creando funciones para esa base de datos, entiendo que una funcion sirve para acortar el codigo y para usarlas con cualquier base de datos, eso no esta pasando