Вы находитесь на странице: 1из 11

DESENCADENADORES (TRIGGERS) Y CURSORES.

Introducción

En contenidos tratados anteriormente se estudió cómo crear objetos de tipo vistas y


funciones para una base de datos. Se veía cómo estos nuevos objetos facilitaban el
trabajo con la base de datos y la interacción con los datos dentro de las tablas.
El lenguaje PL/pgSQL permite la creación de otros tipos de objetos denominados
desencadenadores (triggers en inglés) como vía de ejecutar funciones de forma
automática dentro del gestor de base de datos, sin necesidad de que sea el usuario
quien mande a ejecutar una operación determinada.
Otro elemento que se trabajó fue cómo devolver un conjunto de tuplas en una vista,
que cumplieran una condición determinada. ¿Qué pasa si de todas esas tuplas
resultantes sólo interesan determinados campos? Para ello se necesita un mecanismo
que trabaje con una fila o un pequeño bloque de filas cada vez. Los cursores son una
extensión de los conjuntos de resultados que proporcionan dicho mecanismo.
A continuación se abordan algunos de los elementos importantes sobre estas nuevas
funcionalidades, desencadenadores (Triggers) y cursores.

Desarrollo
TRIGGER
Se han visto las ventajas que la funciones proporcionan al simplificar acciones en una
base de datos. Pero estas acciones requieren la intervención de una persona
encargada de ejecutar las funciones cuando se requiera de su actuación. Los Triggers
al contrario son funciones que se ejecutan de forma automática en respuesta a ciertos
eventos que ocurren en la base de datos.
Un trigger es una función que se ejecuta de forma automática cuando se cumple una
condición establecida al realizar una operación sobre la base de datos. Un Trigger es
una acción en cadena que empieza cuando un evento específico ocurre sobre una
tabla específica.

¿Cuándo entra en vigor un trigger?


Antes o después de una inserción (INSERT).
Antes o después de una actualización (UPDATE).
Antes o después de una eliminación (DELETE).

El uso de los triggers está muy vinculado con la realización de acciones para auditar y
monitorear la actividad de cambio de datos dentro de una base de datos. Permiten
validar datos, cambiando o negando acciones como INSERT, UPDATE y DELETE en
una tabla. Además su funcionalidad les permite preservar la consistencia y claridad de
los datos ejecutando acciones relacionadas con otras tablas.
Ventajas de los triggers:
Pueden consultar otras tablas e incluir instrucciones SQL complejas.
Son especialmente útiles para exigir reglas o requisitos complejos.
Son útiles para exigir la integridad referencial, que conserva las relaciones
definidas entre tablas cuando se agregan, actualizan o eliminan filas en esas
tablas.
Son automáticos, se activan al efectuarse modificaciones en los datos de la
tabla, como una entrada manual o una acción de la aplicación.
Pueden realizar cambios en cascada a través de tablas relacionadas de la base
de datos, al igual que cuando se define las cláusulas ON DELETE y ON
UPDATE al definir restricciones de integridad referencial al crear tablas.
Pueden exigir restricciones más complejas que las definidas con restricciones
CHECK.
Ofrecen un mayor control sobre la Base de Datos.

Definición de los triggers:


La definición de un trigger consta de dos partes:
1. La definición de la función asociada al trigger que es la que ejecuta la acción en
respuesta al evento (INSERT, UPDATE, DELETE).
2. La definición formal de trigger que indicará:
a) De qué tabla se esperarán los eventos.
b) A qué tipo de evento se responderá.

Funciones Tipo Trigger:


Una función tipo trigger es similar a una función normal, salvo por algunos detalles:
El tipo de retorno ya no es un tipo normal de PostgreSQL, sino el tipo especial
trigger.
Dependiendo de las acciones del trigger, el parámetro en el comando RETURN
puede variar.

Ejemplo:

CREATE OR REPLACE FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] )


[ RETURNS trigger ]
AS $$
DECLARE
Variable;
Variable;
BEGIN
sentencia;
END;
$$
LANGUAGE ‘plpgsql’;

Luego de elaborada la función trigger, se debe definir formalmente el trigger de este


modo:

CREATE OR REPLACE TRIGGER nombre_trigger


[ AFTER | BEFORE ] [ INSERT | UPDATE | DELETE ]
ON nombre_tabla
FOR EACH [ROW | STATEMENT]
EXECUTE PROCEDURE function;

Argumentos:
nombre_trigger: Es el nombre del desencadenador.

[ AFTER | BEFORE ]: Define el momento en que el desencadenador entra en acción.


Puede ser BEFORE (antes) ó AFTER (después), para indicar que el disparador se
ejecute antes o después que la sentencia que lo activa.

[ INSERT | UPDATE | DELETE ]: Indica la clase de sentencia que activa al disparador.


Puede ser INSERT, UPDATE, ó DELETE. Por ejemplo, un disparador BEFORE para
sentencias INSERT podría utilizarse para validar los valores a insertar.

nombre_tabla: Nombre tabla a la que está asociado el disparador.

FOR EACH [ROW | STATEMENT]: Para cada fila ó para cada sentencia.

EXECUTE PROCEDURE function: Es la sentencia que se ejecuta cuando se activa el


disparador. Si se desean ejecutar múltiples sentencias, deben colocarse entre BEGIN y
END.

Los desencadenadores pueden incluir cualquier número y clase de instrucciones SQL.


Un desencadenador está diseñado para comprobar o cambiar los datos; no debe
devolver datos al usuario.

PostgreSQL también maneja algunas variables al momento de ejecutar un trigger,


estas son:

NEW: Variable compuesta que almacena los nuevos valores de la tupla que se está
Modificando.

OLD: Variable compuesta que almacena los valores antiguos de la tupla que se está
modificando.

TG_OP: Variable tipo string que indica qué tipo de evento está ocurriendo (INSERT,
UPDATE, DELETE).

TG_ARGV: Variable tipo arreglo que almacena los parámetros de la función del trigger,
los cuales se pueden acceder de la forma TG_ARGV[0], TG_ARGV[1], etc.

Revisar el siguiente ejemplo:

Sea la tabla Producto en la base de datos:

PRODUCTO (producto_id, nombre, tipo, cantidad, precio_compra, precio_venta).

La tabla PRODUCTO tiene la capacidad de almacenar la información más actual e


importante de los productos para una tienda de computadoras, pero hay otro tipo de
información que no es capaz de almacenar, que es la información del cambio de datos.
La tabla PRODUCTO no tiene memoria de los cambios que han sufrido sus tuplas, de
manera que si alguien cambia el precio de venta de un artículo no hay forma de
obtener el precio anterior. Si alguien borra un artículo, tampoco se sabe qué artículo ha
sido borrado ni por quién.
Esto conlleva a una de las grandes áreas de utilización de los triggers, la auditoría de
tablas.

Entonces, ¿cuáles son las acciones que se deben realizar con un trigger?
Se necesita llevar un registro de todos los cambios relevantes en la tabla
PRODUCTO, comenzando por tener un seguimiento de los cambios en los
precios de los productos.

Se debe crear una tabla que almacene los cambios de precio en la tabla PRODUCTO,
la cual se llamará PRODUCTO_ACTUALIZADO.

PRODUCTO_ACTUALIZADO (producto_id, nombre, precio_anterior,


precio_actualizado, autor, fecha_cambio).

La función que ejecutará el trigger quedaría de la siguiente forma:

CREATE FUNCTION producto_actualizado_tri()


RETURN trigger
AS $$
BEGIN
IF (TG_OP = 'UPDATE') THEN
INSERT INTO PRODUCTO_ACTUALIZADO VALUES (OLD.producto_id,
OLD.nombre, OLD.precio_venta, NEW.precio_venta, current_user,
current_date);
END IF;
RETURN NULL;
END;
$$
Language 'plpgsql';

Se está insertando para la tabla PRODUCTO_ ACTUALIZADO los datos asociados a


los cambios realizados en la tabla PRODUCTO.

Ahora se crea el trigger que llamará la función anterior:

CREATE TRIGGER actualizar_producto


AFTER UPDATE ON PRODUCTO
FOR EACH ROW
EXECUTE PROCEDURE producto_actualizado_tri();

Al trigger se le especifica que siempre se ejecutará después que se actualice la tabla


PRODUCTO, de esta forma siempre que se actualicen valores en la tabla PRODUCTO,
los valores antiguos y nuevos se insertarán en la tabla PRODUCTO_ACTUALIZADO.
Los triggers son objetos de la BD, por lo tanto además del CREATE TRIGGER se les
puede aplicar el ALTER TRIGGER para modificar un desencadenador y el DROP
TRIGGER para eliminarlo. El hecho de eliminar un desencadenador no afecta a la tabla
ni a los datos en los que está basado. Si se elimina una tabla, se eliminarán
automáticamente todos los desencadenadores asociados a ella.
Ya se han visto todas las ventajas de los triggers, pero como todas las cosas ellos
también tienen sus desventajas.

Desventajas de los Triggers:


Hay que definir con anticipación la tarea que realizará.
Peligro de pérdida en reorganizaciones.
Nunca se puede llamar directamente.
No se desarrollan pensando en un solo registro, los mismos deben funcionar en
conjunto con los datos ya que se disparan por operación y no por registro.
Se definen por funcionalidad, no se puede poner en uno solo las funciones
asociadas al INSERT, UPDATE y DELETE a la vez.
No se pueden utilizar en tablas temporales.

CURSORES
Las operaciones de una base de datos relacional actúan en un conjunto completo de
filas. El conjunto de filas que devuelve una instrucción SELECT está compuesto por
todas las filas que satisfacen las condiciones de la cláusula WHERE de la instrucción.
Este conjunto completo de filas que devuelve la instrucción se conoce como el conjunto
de resultados. Las aplicaciones no siempre pueden trabajar de forma efectiva con el
conjunto de resultados completo si lo toman como una unidad. Estas aplicaciones
necesitan un mecanismo que trabaje con una fila o un pequeño bloque de filas cada
vez. Precisamente los cursores representan consultas SELECT de SQL que devuelven
más de un resultado y que permiten el acceso a cada fila de una consulta.

Los cursores amplían el procesamiento de los resultados de una consulta porque:


Permiten situarse en filas específicas del conjunto de resultados.
Recuperan una fila o bloque de filas de la posición actual en el conjunto de
resultados.
Aceptan modificaciones de los datos de las filas en la posición actual del
conjunto de resultados
Aceptan diferentes grados de visibilidad para los cambios que realizan otros
usuarios en la información de la base de datos que se presenta en el conjunto
de resultados.
Proporcionan instrucciones en secuencias de comandos, procedimientos
almacenados y acceso de desencadenadores a los datos de un conjunto de
resultados.

Los cursores se utilizan principalmente en procedimientos almacenados o funciones,


desencadenadores y secuencias de comandos de SQL, a fin de dejar disponible el
contenido de un conjunto de resultados para otras instrucciones SQL.

Procesamiento de los Cursores


Los cursores se procesan en 4 pasos:
1. Declarar el cursor
2. Abrir el cursor. Tras abrir el cursor, el puntero del cursor señalará a la primera
fila (si existe).
3. Procesar el cursor. La instrucción FETCH permite recorrer el cursor registro a
registro hasta que el puntero llegue al final (se dice que hasta que el cursor esté
vacío).
4. Cerrar el cursor.

Declarar el Cursor
Sintaxis:
DECLARE
cursor_name CURSOR FOR select_statement;

Este comando declara un cursor. Pueden definirse varios cursores en una rutina, pero
cada cursor en un bloque debe tener un nombre único.

Argumentos:
cursor_name: Especifica el nombre del cursor.

select_statement: Es una instrucción SELECT estándar que define el conjunto de


resultados del cursor.

Ejemplo:
DECLARE
curs1 refcursor;
curs2 CURSOR FOR SELECT * FROM empleado;

Los dos cursores declarados anteriormente tienen el tipo de datos refcursor, pero el
primer cursor (curs1) puede ser usado para cualquier consulta, mientras que el
segundo es específico para la consulta SELECT * FROM empleado.

Comandos para el trabajo con cursores


OPEN cursor

Esta sentencia abre el cursor, lo que significa:


1. Reservar memoria suficiente para el cursor.
2. Ejecutar la sentencia SELECT a la que se refiere el cursor.
3. Colocar el puntero en la primera fila.

FETCH [selector] [count] {IN I FROM} cursor INTO target


La sentencia FETCH es la encargada de recorrer el cursor e ir procesando los valores
del mismo:

FETCH cursor INTO listaDeVariables

Esta instrucción almacena el contenido de la fila a la que apunta actualmente el puntero


en la lista de variables indicada, que tiene que tener el mismo tipo y número que las
columnas representadas en el cursor. Tras esta instrucción el puntero de registros
avanza a la siguiente posición. Esta instrucción se coloca dentro de un bucle a fin de ir
procesando cada fila del cursor.

Esta instrucción cuenta con un selector que indica la dirección del recorrido, que puede
ser:

FORWARD: Selecciona la(s) siguiente(s) filas. Es el valor por defecto si se omite


el selector.

BACKWARD: Selecciona la(s) fila(s) anterior(es).

RELATIVE: Palabra sin significado para compatibilidad con SQL92.

count: determina cuántas filas hay que seleccionar. Puede ser uno de los siguientes:

#: Un entero con signo que especifica cuántas filas hay que seleccionar. UN
entero negativo es equivalente a cambiar el sentido de la selección (Forward o
Backward)

ALL: Devuelve todas las filas restantes.

NEXT: Equivalente a especificar un "count" de 1.

PRIOR: Equivalente a especificar un "count" de -1.

cursor: nombre de un cursor abierto.

Ejemplo:
FETCH cursorProvincias INTO v_nombre, v_poblacion;

Una instrucción FETCH lee una sola fila y su contenido lo almacena en variables. Por
ello se usa siempre dentro de bucles:

LOOP
FETCH cursorProvincias INTO (v_nombre, v_poblacion);
EXIT WHEN... --aquí se pondría la condición de salida...
--instrucciones de proceso de los datos del cursor
END LOOP;

CLOSE cursor (CLOSE cursor)


Al cerrar el cursor se libera la memoria que ocupa y se impide su procesamiento.
Tras cerrar un cursor este podría ser abierto de nuevo.

Atributos de los Cursores


IS OPEN: Devuelve verdadero si el cursor ya está abierto.

Ejemplo:
cursorProvincias IS OPEN;

NOT FOUND: Devuelve verdadero si la última instrucción FETCH no devolvió


ningún valor.

Ejemplo:
BEGIN
OPEN cursorProvincias;
LOOP
FETCH cursorProvincias INTO v_nombre,v_poblacion;
EXIT WHEN NOT FOUND;
END LOOP;
CLOSE cursorProvincias;
END;

En el ejemplo anterior se recorre el cursor hasta que el FETCH no devuelve ninguna


fila.

FOUND: Devuelve verdadero si el último FETCH devolvió una fila.

Cursores con parámetros:


En muchas ocasiones se podría desear que el resultado de un cursor dependa de una
variable. Por ejemplo al presentar una lista de personal, hacer que aparezca el cursor
de un determinado departamento y puesto de trabajo.
Para hacer que el cursor varíe según esos parámetros, se han de indicar los mismos
en la declaración del cursor. Para ello se pone entre paréntesis su nombre y tipo tras el
nombre del cursor en la declaración.

Ejemplo:
DECLARE
cur_personas CURSOR (dep NUMBER, pue VARCHAR2 (20)) FOR
SELECT nombre, apellidos
FROM empleados
WHERE departamento=dep AND puesto=pue;
BEGIN
OPEN cur_personas (12,’administrativo’);
.....
CLOSE cur_personas;
END
Es al abrir el cursor cuando se indica el valor de los parámetros, lo que significa que se
puede abrir varias veces el cursor y que éste obtenga distintos resultados dependiendo
del valor del parámetro.

Se pueden indicar los parámetros también en el bucle FOR:

Ejemplo
DECLARE
cur_personas CURSOR (dep NUMBER, pue VARCHAR2 (20)) FOR
SELECT nombre, apellidos
FROM empleados
WHERE departamento=dep AND puesto=pue;
BEGIN
FOR r IN cur_personas (12,’administrativo’)
LOOP
.....
END LOOP;
END:

Desventajas de los cursores:


Recuperar una fila del cursor puede resultar en un retraso, lo que se debe al
tiempo necesario para enviar la petición al servidor y esperar los datos.
Reservan recursos en el servidor, como por ejemplo locks, packages, procesos,
almacenamiento temporal, etc.
Si un cursor no se cierra de manera correcta, el recurso no será liberado hasta
que la sesión SQL (conexión) sea cerrada. Este desperdicio de recursos en el
servidor puede llevar no sólo a una degradación del rendimiento, sino también a
fallos más graves.

Conclusiones
Hasta aquí se vieron los elementos básicos de dos contenidos muy importantes y de
amplia utilización en el trabajo con bases de datos: los triggers y los cursores.
El uso de los triggers y cursores en una base de datos garantiza una mayor seguridad y
fiabilidad en las consultas; pero un uso desmedido de ambos trae consigo demora en la
ejecución de las consultas y un gran consumo de recurso por parte del servidor de
base de datos.

Вам также может понравиться