Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% encontró este documento útil (0 votos)
76 vistas17 páginas

Triggers Modulo

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1/ 17

TRIGGERS (DISPARADORES)

Hemos visto las ventajas que la funciones nos proporcionan al


simplificar acciones en nuestra 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.

Una de las funcionalidades disponibles en PostgreSQL son los


denominados disparadores (triggers).

Un disparador no es otra cosa que una acción definida en una tabla


de nuestra base de datos y ejecutada automáticamente por una
función programada por nosotros. Esta acción se activará, según
la definamos, cuando realicemos un INSERT, un UPDATE ó un
DELETE en la susodicha tabla.

Cuando se ejecuta 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 un borrado (DELETE)

Durante la ejecución de una aplicación de base de datos, hay


ocasiones que se requiere realizar una o más acciones de forma
automática, si se produce un evento en específico. Es decir, que la
primera acción provoca la ejecución de las siguientes acciones. Los
denominados Triggers o disparadores son el mecanismo de
activación, que posee SQL para entregar esta capacidad.

Antes de definir el disparador tendremos que definir el


procedimiento almacenado (función) que se ejecutará cuando
nuestro disparador se active.
El procedimiento almacenado usado por nuestro disparador se
puede programar en cualquiera de los lenguajes de procedimientos
disponibles, entre ellos, el proporcionado por defecto cuando se
instala PostgreSQL, PL/pgSQL.

Características y reglas a seguir

A continuación teneis algunas de las características y reglas más


importantes a tener en cuenta, cuando definamos un disparador y/ó
programemos un procedimiento almacenado que se vaya a utilizar
por un disparador:

1. El procedimiento almacenado que se vaya a utilizar por el disparador debe de


definirse e instalarse antes de definir el propio disparador.

2. Un procedimiento que se vaya a utilizar por un disparador no puede tener


argumentos y tiene que devolver el tipo "trigger".

3. Un mismo procedimiento almacenado se puede utilizar por múltiples


disparadores en diferentes tablas.

4. Procedimientos almacenados utilizados por disparadores que se ejecutan una


sola vez per comando SQL (statement-level) tienen que devolver siempre
NULL.

5. Procedimientos almacenados utilizados por disparadores que se ejecutan una


vez per linea afectada por el comando SQL (row-level) pueden devolver una
fila de tabla.

6. Procedimientos almacenados utilizados por disparadores que se ejecutan una


vez per fila afectada por el comando SQL (row-level) y ANTES de ejecutar el
comando SQL que lo lanzó, pueden:
A. Retornar NULL para saltarse la operación en la fila afectada.
B. Ó devolver una fila de tabla (RECORD)

7. Procedimientos almacenados utilizados por disparadores que se ejecutan


DESPUES de ejecutar el comando SQL que lo lanzó, ignoran el valor de
retorno, asi que pueden retornar NULL sin problemas.

8. En resumen, independendientemente de cómo se defina un disparador, el


procedimiento almacenado utilizado por dicho disparador tiene que devolver ó
bien NULL, ó bien un valor RECORD con la misma estructura que la tabla que
lanzó dicho disparador.

9. Si una tabla tiene más de un disparador definido para un mismo evento


(INSERT,UPDATE,DELETE), estos se ejecutarán en orden alfabético por el
nombre del disparador. En el caso de disparadores del tipo ANTES / row-level,
la file retornada por cada disparador, se convierte en la entrada del siguiente.
Si alguno de ellos retorna NULL, la operación será anulada para la fila
afectada.

10. Procedimientos almacenados utilizados por disparadores pueden ejecutar


sentencias SQL que a su vez pueden activar otros disparadores. Esto se
conoce como disparadores en cascada. No existe límite para el número de
disparadores que se pueden llamar pero es responsabilidad del
programador el evitar una recursión infinita de llamadas en la que un
disparador se llame así mismo de manera recursiva.

Otra cosa que tenemos que tener en cuenta es que, por cada disparador que
definamos en una tabla, nuestra base de datos tendrá que ejecutar la función
asociada a dicho disparador. El uso de disparadores de manera incorrecta ó
inefectiva puede afectar significativamente al rendimiento de nuestra base de
datos.

Variables especiales en PL/pgSQL


Cuando una función escrita en PL/pgSQL es llamada por un disparador tenemos
ciertas variable especiales disponibles en dicha función. Estas variables son las
siguientes:

NEW
Tipo de dato RECORD; Variable que contiene la nueva fila de la tabla para las
operaciones INSERT/UPDATE en disparadores del tipo row-level. Esta variable es
NULL en disparadores del tipo statement-level.

OLD
Tipo de dato RECORD; Variable que contiene la antigua fila de la tabla para las
operaciones UPDATE/DELETE en disparadores del tipo row-level. Esta variable
es NULL en disparadores del tipo statement-level.

TG_NAME
Tipo de dato name; variable que contiene el nombre del disparador que está
usando la función actualmente.

TG_WHEN
Tipo de dato text; una cadena de texto con el valor BEFORE o AFTER
dependiendo de como el disparador que está usando la función actualmente ha
sido definido

TG_LEVEL
Tipo de dato text; una cadena de texto con el valor ROW o STATEMENT
dependiendo de como el disparador que está usando la función actualmente ha
sido definido

TG_OP
Tipo de dato text; una cadena de texto con el valor INSERT, UPDATE o DELETE
dependiendo de la operación que ha activado el disparador que está usando la
función actualmente.

TG_RELID
Tipo de dato oid; el identificador de objeto de la tabla que ha activado el
disparador que está usando la función actualmente.

TG_RELNAME
Tipo de dato name; el nombre de la tabla que ha activado el disparador que está
usando la función actualmente. Esta variable es obsoleta y puede desaparacer en
el futuro. Usar TG_TABLE_NAME.

TG_TABLE_NAME
Tipo de dato name; el nombre de la tabla que ha activado el disparador que está
usando la función actualmente.

TG_TABLE_SCHEMA
Tipo de dato name; el nombre de la schema de la tabla que ha activado el
disparador que está usando la función actualmente.

TG_NARGS
Tipo de dato integer; el número de argumentos dados al procedimiento en la
sentencia CREATE TRIGGER.

TG_ARGV[]
Tipo de dato text array; los argumentos de la sentencia CREATE TRIGGER. El
índice empieza a contar desde 0. Indices inválidos (menores que 0 ó
mayores/iguales que tg_nargs) resultan en valores nulos.

Forma general o estructura general de los Triggers


(1)CREATE TRIGGER nombreTrigger
(2)BEFORE|AFTER|INSTEAD OF AlgúnEvento
ON nombreTabla
(3)WHEN (condición)
(4)Action

Ahora creamos una tabla para poder definir nuestro primer


disparador:

CREATE TABLE numeros(


numero bigint NOT NULL,
cuadrado bigint,
cubo bigint,
raiz2 real,
raiz3 real,
PRIMARY KEY (numero)
);

Después tenemos que crear una función en PL/pgSQL para ser usada por nuestro
disparador. Nuestra primera función es la más simple que se puede definir y lo
único que hará será devolver el valor NULL:

CREATE OR REPLACE FUNCTION proteger_datos() RETURNS TRIGGER AS


$proteger_datos$
DECLARE
BEGIN
--
-- Esta funcion es usada para proteger datos en un tabla
-- No se permitira el borrado de filas si la usamos
-- en un disparador de tipo BEFORE / row-level
--
RETURN NULL;
END;
$proteger_datos$ LANGUAGE plpgsql;

A continuación definimos en la tabla numeros un disparador del tipo BEFORE /


row-level para la operación DELETE. Más adelante veremos cómo funciona:

CREATE TRIGGER proteger_datos BEFORE DELETE


ON numeros FOR EACH ROW
EXECUTE PROCEDURE proteger_datos();

La definición de nuestra tabla ha quedado así:

CREATE TABLE numeros


(
numero bigint NOT NULL,
cuadrado bigint,
cubo bigint,
raiz2 real,
raiz3 real,
CONSTRAINT numeros_pkey PRIMARY KEY (numero)
)
WITH (
OIDS=FALSE
);
ALTER TABLE numeros
OWNER TO postgres;

-- Trigger: proteger_datos on numeros

-- DROP TRIGGER proteger_datos ON numeros;

CREATE TRIGGER proteger_datos


BEFORE DELETE
ON numeros
FOR EACH ROW
EXECUTE PROCEDURE proteger_datos();

Ahora vamos a definir una nueva función un poco más complicada


y un nuevo disparador en nuestra tabla numeros:

Función

CREATE OR REPLACE FUNCTION rellenar_datos() RETURNS TRIGGER AS


$rellenar_datos$
DECLARE
BEGIN

NEW.cuadrado := power(NEW.numero,2);
NEW.cubo := power(NEW.numero,3);
NEW.raiz2 := sqrt(NEW.numero);
NEW.raiz3 := cbrt(NEW.numero);

RETURN NEW;
END;
$rellenar_datos$ LANGUAGE plpgsql;

trigger
CREATE TRIGGER rellenar_datos BEFORE INSERT OR UPDATE
ON numeros FOR EACH ROW
EXECUTE PROCEDURE rellenar_datos();

Ahora vamos a ver como los disparadores que hemos definido en la tabla numeros
funcionan:
INSERT INTO numeros (numero) VALUES (2);

Mire lo que paso en la tabla números


Resultado
Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
De nuevo veamos como los disparadores que hemos definido en la tabla numeros
funcionan:
INSERT INTO numeros (numero) VALUES (3);

Mire los que paso en la tabla números


Resultado
Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 3 9 27 1.73205 1.44225

De nuevo veamos como los disparadores que hemos definido en la tabla numeros
funcionan:

UPDATE numeros SET numero = 4 WHERE numero = 3;

Mire lo que paso en la tabla números


Resultado
Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 4 16 64 2 1.5874

Hemos realizado 2 INSERT y 1 UPDATE. Esto significa que por cada uno de estos
comandos el sistema ha ejecutado la función rellenar_datos(), una vez por cada
fila afectada y antes de actualizar la tabla numeros.

Como vemos, nosotros solamente hemos actualizado la columna numero, pero al


listar el contenido de nuestra tabla vemos como el resto de columnas (cuadrado,
cubo, raiz2 y raiz3) también contienen valores.

De esta actualización se ha encargado la función rellenar_datos()


llamada por nuestro disparador. Vamos a analizar lo que hace esta
función

NEW.cuadrado := power(NEW.numero,2);
NEW.cubo := power(NEW.numero,3);
NEW.raiz2 := sqrt(NEW.numero);
NEW.raiz3 := cbrt(NEW.numero);

RETURN NEW;

 Cuando ejecutamos el primer INSERT (numero = 2), el disparador rellenar_datos


llama a la función rellenar_datos() una vez.
 El valor de la variable NEW al empezar a ejecutarse rellenar_datos() es
numero=2, cuadrado=NULL, cubo=NULL, raiz2=NULL, raiz3=NULL.
 Nuestra tabla todavía no contiene ninguna fila.
 A continuación calculamos el cuadrado, el cubo, la raiz cuadrada y la raiz cubica
de 2 y asignamos estos valores a NEW.cuadrado, NEW.cubo, NEW.raiz2 y
NEW.raiz3.
 El valor de la variable NEW antes de la sentencia RETURN NEW es ahora
numero=2, cuadrado=4, cubo=8, raiz2=1.41421, raiz3=1.25992
 Con la sentencia RETURN NEW, retornamos la fila (RECORD) almacenada en
la variable NEW, y salimos de la función rellenar_datos(). El sistema almacena
entonces el RECORD contenido en NEW en la tabla numeros

De la misma manera funciona el disparador proteger_datos cuando ejecutamos una


sentencia DELETE. Antes de borrar nada ejecutará la función proteger_datos().

Esta función retorna el valor NULL y esto significa, según la regla 6.1 definida en
este artículo, que para la fila afectada no se ejecutará el comanado DELETE. Por
eso y mientras este disparador este instalado será imposible de borrar nada de la
tabla numeros.

DELETE FROM numeros;

Mire lo que paso en la tabla números


Resultado
Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 4 16 64 2 1.5874
Ahora, vamos a desinstalar nuestros dos disparadores proteger_datos y
rellenar_datos.
Para eliminar disparadores
DROP TRIGGER

DROP TRIGGER proteger_datos ON numeros;

DROP TRIGGER rellenar_datos ON numeros;

Revise el estema de la base de datos y vera lo siguiente, se


generó un cambio.

CREATE TABLE numeros


(
numero bigint NOT NULL,
cuadrado bigint,
cubo bigint,
raiz2 real,
raiz3 real,
CONSTRAINT numeros_pkey PRIMARY KEY (numero)
)
WITH (
OIDS=FALSE
);
ALTER TABLE numeros
OWNER TO postgres;

Ahora crearemos un disparador único para las sentencias INSERT, UPDATE y


DELETE. Este nuevo disparador utilizará una nueva función en la que tendremos
que tener en cuenta que tipo de comando ha activado el disparador, si queremos
retornar el valor correcto. Para ello utilizaremos la variable TG_OP.

No olvide eliminar las funciones anteriores

drop FUNCTION proteger_datos()

drop FUNCTION rellenar_datos()


Nota: primero se eliminar las disparadores y luego las funciones

Function proteger_y_rellenar_datos()
CREATE OR REPLACE FUNCTION proteger_y_rellenar_datos() RETURNS
TRIGGER AS $proteger_y_rellenar_datos$
DECLARE
BEGIN

IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE' ) THEN

NEW.cuadrado := power(NEW.numero,2);
NEW.cubo := power(NEW.numero,3);
NEW.raiz2 := sqrt(NEW.numero);
NEW.raiz3 := cbrt(NEW.numero);
RETURN NEW;

ELSEIF (TG_OP = 'DELETE') THEN


RETURN NULL;

END IF;
END;
$proteger_y_rellenar_datos$ LANGUAGE plpgsql

Tigger proteger_y_rellenar_datos()

CREATE TRIGGER proteger_y_rellenar_datos BEFORE INSERT OR UPDATE


OR DELETE
ON numeros FOR EACH ROW
EXECUTE PROCEDURE proteger_y_rellenar_datos();

Y todo seguirá funcionando de la misma manera que con los dos disparadores del
comienzo:
SELECT * from numeros;
Mire lo que paso en la tabla números
Resultado
numero cuadrado cubo raiz2 raiz3
2 4 8 1.41421 1.25992
4 16 64 2 1.5874

INSERT INTO numeros (numero) VALUES (5);


Mire lo que paso en la tabla números
Resultado
Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 4 16 64 2 1.5874
Editar Eliminar 5 25 125 2.23607 1.70998

UPDATE numeros SET numero = 10 WHERE numero = 5;


Mire lo que paso en la tabla números
Resultado
Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 4 16 64 2 1.5874
Editar Eliminar 10 100 1000 3.16228 2.15443

DELETE FROM numeros where numero =10;


Mire lo que paso en la tabla números
Resultado
Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 4 16 64 2 1.5874
Editar Eliminar 10 100 1000 3.16228 2.15443

Por último y antes de terminar, vamos a definir un disparador del tipo statement-
level que se ejecute después de nuestras sentencias INSERT, UPDATE y DELETE.
La función ejecutada por este disparador grabará datos de la ejecución en la tabla
cambios (esto no sirve para mucho en la vida real, pero como ejemplo está bien
para ver cómo funciona).

CREATE TABLE cambios(


timestamp_ TIMESTAMP WITH TIME ZONE default NOW(),
nombre_disparador text,
tipo_disparador text,
nivel_disparador text,
comando text
);
La función la podemos definir así:
CREATE OR REPLACE FUNCTION grabar_operaciones() RETURNS TRIGGER
AS $grabar_operaciones$
DECLARE
BEGIN

INSERT INTO cambios (


nombre_disparador,
tipo_disparador,
nivel_disparador,
comando)
VALUES (
TG_NAME,
TG_WHEN,
TG_LEVEL,
TG_OP
);

RETURN NULL;
END;
$grabar_operaciones$ LANGUAGE plpgsql;

Y el disparador lo definimos de la siguiente forma:


CREATE TRIGGER grabar_operaciones AFTER INSERT OR UPDATE OR
DELETE
ON numeros FOR EACH STATEMENT
EXECUTE PROCEDURE grabar_operaciones();
Miremos con funciona

SELECT * from cambios


No se encontraron filas.

Tiempo total de ejecución: 1.000 ms

SQL ejecutada.

INSERT INTO numeros (numero) VALUES (100);


Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 4 16 64 2 1.5874
Editar Eliminar 10 100 1000 3.16228 2.15443
Editar Eliminar 100 10000 1000000 10 4.64159
SELECT * from cambios ;

timestamp_ nombre_disparador tipo_disparador nivel_disparador comando


2015-08-16 19:17:26.696-05 grabar_operaciones AFTER STATEMENT INSERT

UPDATE numeros SET numero = 1000 WHERE numero = 100;


Acciones numero cuadrado cubo raiz2 raiz3
Editar Eliminar 2 4 8 1.41421 1.25992
Editar Eliminar 4 16 64 2 1.5874
Editar Eliminar 10 100 1000 3.16228 2.15443
Editar Eliminar 1000 1000000 1000000000 31.6228 10

SELECT * from cambios ;

timestamp_ nombre_disparador tipo_disparador nivel_disparador comando


2015-08-16 19:17:26.696-05 grabar_operaciones AFTER STATEMENT INSERT
2015-08-16 19:19:45.034-05 grabar_operaciones AFTER STATEMENT UPDATE

Ejercicio 1

Crear una base de datos login, una tabla llamada usuario

CREATE TABLE usuario


(
pat_pad character varying(20),
mat_pad character varying(20),
nom_pad character varying(20),
nombre character varying(60)
)

FUNCIÓN
CREATE OR REPLACE FUNCTION actualizar_nombre() RETURNS TRIGGER
AS $trigger_ejemplo$
BEGIN
NEW.nombre := NEW.pat_pad || ' ' || NEW.mat_pad || ' ' || NEW.nom_pad ;
RETURN NEW;
END;
$trigger_ejemplo$ LANGUAGE plpgsql;
TRIGGER
CREATE TRIGGER trigger_ejemplo
BEFORE INSERT OR UPDATE ON usuario
FOR EACH ROW EXECUTE PROCEDURE actualizar_nombre();

Luego de ejecutar, esto debe llenar la base de datos Y mirar lo que sucede
con nombre
Ejercicio 2

Crear las tablas

CREATE TABLE otratabla


(
campo1 character varying(20),
campo2 character varying(20)
)

CREATE TABLE tablaorigen


(
campo1 character varying(20),
campo2 character varying(20)
)
Ejecute la función
CREATE OR REPLACE FUNCTION pa_grabarotratabla()
RETURNS trigger AS
$BODY$
begin
insert into otratabla(campo1,campo2)
values(NEW.campo1,NEW.campo2);
RETURN NEW;
end;$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

CREATE TRIGGER tr_grabarotratabla


AFTER INSERT
ON tablaorigen
FOR EACH ROW
EXECUTE PROCEDURE pa_grabarotratabla();

Llene la tablaorigen y verifique que pasa con otratabla

También podría gustarte