Vous êtes sur la page 1sur 58
Autor: Luis Felipe Wanumen Silva 1 ENCICLOPEDIA CONOCIENDO TOMO XLII CUADERNO DE TRIGGERS ELABORADO POR: LUIS FELIPE WANUMEN SILVA INGENIERO DE SISTEMAS Y AUTOR DE LA ENCICLOPEDIA CONOCIENDO CONTIENE RESUMEN DE SUS CLASES, AMPLIACIÓN DE EXPLICACIONES, EJERCICIOS RESUELTOS DE TRIGGERS Y ALGO MÁS. PRIMERA VERSIÓN AUN NO REVISADA SANTAFE DE BOGOTA D.C. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva AGOSTO DE 2003. 2 Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 3 1. PRIMERA UNIDAD: INTRODUCCIÓN A LOS TRIGGERS 1.1. DEFINICIÓN Los triggers son procedimientos almacenados que se disparan cuando se presenta una acción sobre una tabla, como una inserción, una actualización o un borrado de registros. En la definición del trigger, se especifica que acciones desencadenan la ejecución del trigger. 1.2. OBJETIVO DE LOS TRIGGERS Validar inserciones, actualizaciones o modificaciones, pero es bien importante mencionar que tales validaciones por pura estética y coherencia con el lenguaje SQL, no deberían ser validaciones que se puedan hacer directamente en la definición de la tabla. Por ejemplo validar que una entrada para un campo sea: SI o NO, es algo que debería hacerse directamente en la definición de la tabla y no se justifica la creación de un trigger para llevar a cabo dicha tarea, pero bueno, no falta el diseñador de bases de datos que hace este tipo de cosas. (Recordemos que las restricciones a nivel de integridad es mejor realizarlas directamente en la definición de campos de una tabla) 1.3. CONSIDERACIONES SOBRE TRIGGERS Es importante disminuir la cantidad de instrucciones al máximo asociadas con un trigger, debido a que si la base de datos está en operación y recibe varias peticiones de actualización, inserción o actualización, puede verse seriamente afectada el rendimiento del sistema. Recordemos que en un trigger asociado a una tabla, es posible realizar operaciones de inserción, actualización o borrado de registros de otras tablas. En estos casos es conveniente tener en cuenta que posiblemente al realizar dichas operaciones sobre otras tablas, se disparen otros triggers definidos para dichas tablas, lo cual podría llegar incluso a generar un bloqueo, si no se hace un verdadero análisis de las dependencias de los diversos triggers. En el caso fortuito que un trigger tenga demasiadas instrucciones y no se pueda eliminar su cantidad, es aconsejable que se coloquen dichas instrucciones en un procedimiento almacenado y se llame a dicho procedimiento desde el trigger, debido a que el procedimiento almacenado es compilado cuando se guarda y esto hace que se acelere la ejecución del trigger. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 4 2. SEGUNDA UNIDAD: TRIGGERS Y MAS CONCEPTOS BASICOS 2.1. UN TRIGGER SIEMPRE SE BORRA CUANDO SE BORRA LA TABLA ASOCIADA Una de las cosas mas interesantes a tener en cuenta en los triggers, es que los triggers se asocian con una tabla y al eliminarse la tabla a la que se relaciona dicho trigger, se elimina el trigger. Al reves no ocurre, es decir cuando se elimina un trigger no se elimina la tabla a la que hace relacion el trigger. Esta cuestion es una cosa bastante interesante. Explicamos esto mediante el siguiente ejercicio: Creemos la siguiente tabla: create table usuario( codigo int, nombre nvarchar(50) ) Creemos por ejemplo un trigger de inserción llamado “trigger_asociado” relacionado con la tabla usuario: create trigger trigger_asociado on usuario for insert as begin select * from usuario end Vemos que podemos borrar el trigger con la instrucción: drop trigger trigger_asociado y finalmente podemos eliminar la tabla “usuario”: drop table usuario y no salen errores, tal como se muestra a continuación: El problema comienza cuando borramos primero la tabla usuario y luego intentamos borrar el trigger llamado “trigger_asociado”, es decir cuando intentamos ejecutar las sentencias en el siguiente orden: drop table usuario drop trigger trigger_asociado Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva obtenemos un resultado similar al siguiente: 5 Cannot drop the trigger 'trigger_asociado', because it does not exist in the system catalog. En el cual podemos apreciar que si eliminamos la tabla, se eliminan con ella los triggers asociados. 2.2. UN TRIGGER DEBE SER LA PRIMERA SENTENCIA EN ARCHIVO DE LOTES Supongamos que tenemos el siguiente script: create table usuario( codigo int, nombre nvarchar(50) ) create trigger trigger_asociado on usuario for insert as begin select * from usuario end y lo intentamos ejecutar todo junto tal como muestra la siguiente figura: Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 6 Observamos que se producen errores, con lo cual para ejecutar dicho script, se requiere ejecutarlo por partes, es decir: Primero ejecutar la creación de la tabla: Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva Y después la creación del trigger: 7 2.3. MENSAJES EN LA INSERCIÓN Dada la siguiente tabla: Tabla: Continente Id --nombre --- La cual es creada con las siguientes instrucciones: create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50)); queremos que se muestre un mensaje en el analizador de consultas cada vez que el se intente insertar un registro en la tabla. Para cumplir dicho cometido, es necesario crear un trigger similar al siguiente: create trigger inserta_continente Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva on CONTINENTE for insert as print "Insertando en tabla CONTINENTE" Con lo cual al intentar realizar la siguiente inserción: insert into CONTINENTE values('AFRICA') obtenemos el siguiente resultado: Insertando en tabla CONTINENTE (1 filas afectadas) 8 2.4. MENSAJES EN LA ACTUALIZACIÓN Dada la siguiente tabla: Tabla: Continente Id 1 2 3 4 5 nombre AFRICA EUROPA HACIA AMERICA OCEANIA (0 filas afectadas) La cual es creada con las siguientes instrucciones: create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50)); insert into CONTINENTE values('AFRICA') insert into CONTINENTE values('EUROPA') insert into CONTINENTE values('HACIA') insert into CONTINENTE values('AMERICA') insert into CONTINENTE values('OCEANIA') queremos que cada vez que se intente realizar una actualización se muestre un mensaje. Para lograr esto, es necesario crear un trigger similar al siguiente: create trigger actualiza_continente Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva on CONTINENTE for update as print "Actualizando CONTINENTE" 9 De tal suerte que cuando se intenta realizar la actualización sobre el continente “HACIA” tal como se muestra a continuación: update CONTINENTE set nombre = 'ASIA' where id = 3 Obtenemos el siguiente resultado: Actualizando CONTINENTE (1 filas afectadas) 2.5. MENSAJES EN EL BORRADO DE REGISTROS Dada la siguiente tabla: Tabla: Continente Id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA AMERICA OCEANIA RUSIA La cual es creada con las siguientes instrucciones: create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50)); insert into CONTINENTE values('AFRICA') insert into CONTINENTE values('EUROPA') insert into CONTINENTE values('HACIA') insert into CONTINENTE values('AMERICA') insert into CONTINENTE values('OCEANIA') insert into CONTINENTE values('RUSIA') Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 10 Queremos que cada vez que el se intente eliminar un registro de la tabla “CONTINENTE”, se despliegue un mensaje que muestre el registro borrado(el cual se encuentra en la tabla “deleted”), después se muestre la tabla “CONTINENTE” en la cual se pueda apreciar que ya se ha realizado el borrado de dicho registro. Por último, que se deshaga la operación de borrado y se vuelva a mostrar la tabla “CONTINENTE” para verificar que efectivamente se deshizo la operación. Veamos pues el trigger: create trigger elimina_continente on CONTINENTE for delete as if(select count(*) from CONTINENTE, deleted where CONTINENTE.id = deleted.id) = 0 begin print "Eliminando el(los) CONTINENTE(S)" select * from deleted print "La tabla CONTINENTE es:" select * from CONTINENTE print "Se deshizo la eliminación" rollback transaction select * from CONTINENTE end Ahora bien, para probar el trigger, realizamos cualquier operación de eliminación de cualquier registro de la tabla “CONTINENTE”, tal como se muestra a continuación: delete from CONTINENTE where id = 1 El resultado de dicha operación de eliminación es el siguiente: Eliminando el(los) CONTINENTE(S) id nombre 1 AFRICA (1 filas afectadas) La tabla CONTINENTE es: id 2 3 nombre EUROPA HACIA Cuaderno de Triggers Enciclopedia Conociendo Autor: Luis Felipe Wanumen Silva 4 5 6 AMERICA OCEANIA RUSIA 11 (5 filas afectadas) Se deshizo la eliminación id 1 2 3 4 5 6 nombre AFRICA EUROPA HACIA AMERICA OCEANIA RUSIA (6 filas afectadas) Para comprender mejor el ejercicio anteriormente mencionado es importante tener en cuenta que cada vez que se borra un registro, dicho registro se pasa a una tabla temporal denominada “deleted”, con lo cual en dicha tabla podemos consultar los registros que fueron borrados También es importante notar que la instrucción: rollback transaction Deshace la(s) acción(es) anteriormente ejecutada(s). 3. TERCERA UNIDAD: TRIGGERS DE INSERCIÓN 3.1. LA TABLA INSERTED La tabla “inserted” es una tabla temporal que se crea cuando se insertan datos. Para el ejercicio siguiente se parte de la tabla “continente” cuyos datos son: Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva Tabla: Continente Id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA AMERICA OCEANIA RUSIA 12 La cual es creada con las siguientes instrucciones: create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50)); insert into CONTINENTE values('AFRICA') insert into CONTINENTE values('EUROPA') insert into CONTINENTE values('HACIA') insert into CONTINENTE values('AMERICA') insert into CONTINENTE values('OCEANIA') insert into CONTINENTE values('RUSIA') Queremos que se cada vez que se vaya a realizar una inserción, se le muestre al usuario los datos que se van a insertar y posteriormente se muestra la tabla “CONTINENTE” con los datos insertados. Para lograr esto, es necesario crear un trigger de inserción similar al siguiente: create trigger inserta_continente on CONTINENTE for insert as begin print "El(los) dato(s) a insertar:" select * from inserted print "La tabla con datos insertados:" select * from CONTINENTE end De tal suerte que al intentar ejecutar la sentencia de inserción siguiente: insert into CONTINENTE values('AMERICA DEL SUR') Se produzca el siguiente resultado: El(los) dato(s) a insertar: Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva id 7 nombre AMERICA DEL SUR 13 (1 filas afectadas) La tabla con datos insertados: id 1 2 3 4 5 6 7 nombre AFRICA EUROPA HACIA AMERICA OCEANIA RUSIA AMERICA DEL SUR (7 filas afectadas) Observemos que para mostrar los datos a insertar, simplemente basta con hacer una consulta sobre la tabla “inserted”, pues como se ha mencionado en este apartado, dicha tabla, contiene los registros que se van a insertar. Posteriormente al hacer la consulta sobre la tabla “CONTINENTE”, se muestra dicha tabla con el registro insertado, puesto que dicha tabla fue actualizada con la sentencia ejecutada por el usuario. 3.2. INSERCIÓN CONDICIONAL Dada la tabla siguiente: Tabla: Continente Id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA AMERICA OCEANIA RUSIA La cual es creada con las siguientes instrucciones: create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50)); Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva insert into CONTINENTE values('AFRICA') insert into CONTINENTE values('EUROPA') insert into CONTINENTE values('HACIA') insert into CONTINENTE values('AMERICA') insert into CONTINENTE values('OCEANIA') insert into CONTINENTE values('RUSIA') 14 Queremos hacer un trigger que impida la inserción de nombres de continentes existentes, con el ánimo de impedir duplicación de información. Un trigger que impide la inserción de nombres de continentes existentes en la tabla “CONTINENTE” es: create trigger inserta_continente on CONTINENTE for insert as if (select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 begin print "Ya existe este continente:" select * from inserted print "Por tanto los datos no se insertaron:" rollback transaction select * from CONTINENTE end Para comprobar que este trigger realiza el trabajo deseado, sencillamente ejecutemos la siguiente instrucción: insert into CONTINENTE values('AMERICA') y obtendremos el siguiente resultado: Por tanto los datos no se insertaron: Ya existe este continente: id 7 (1 filas afectadas) nombre AMERICA id 1 2 3 4 5 6 (6 filas afectadas) nombre AFRICA EUROPA HACIA AMERICA OCEANIA RUSIA Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 15 Para comprender este ejercicio es necesario tener en cuenta que cuando se va a realizar la inserción, se crea una tabla temporal denominada “inserted”, la cual tiene los siguientes datos: Tabla: inserted id 7 nombre AMERICA También es bueno tener en cuenta que los datos ya han sido insertados y por tanto al ejecutar la sentencia siguiente en el trigger: Select * from CONTINENTE Obtendremos el resultado: id 1 2 3 4 5 6 7 nombre AFRICA EUROPA HACIA AMERICA OCEANÍA RUSIA AMERICA Con lo cual podemos observar que aparece dos veces el nombre de continente “AMERICA”, por tanto el trigger debe mostrar los campos de la tabla “CONTINENTE” que tengan en su parte “nombre” el valor “AMERICA” y dicho valor “AMERICA”, es posible obtenerlo de la tabla “inserted”. Por tanto la pregunta que se debe realizar es: if (select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 De acuerdo al resultado de dicha pregunta, se debe proceder a deshacer la transacción, tal como se muestra a continuación: rollback transaction El resto de instrucciones, simplemente están mostrando al usuario el campo que no se pudo insertar, simplemente haciendo una consulta sobre la tabla “inserted” 3.3. ORDEN DE EJECUCIÓN CON TRIGGERS Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 16 El orden en que se ejecutan las sentencias cuando existen trigger asociados a un tipo de consulta es el siguiente: o o o o Se crean las tablas temporales Se ejecuta la consulta Se ejecuta el trigger Se borran las tablas temporales 3.4. IMPIDIENDO VALORES NO EXISTENTES En el trigger de la sección anterior, se estaba realizando un ejercicio para impedir que el usuario insertara valores repetidos. En esta oportunidad se va a realizar un trigger para evitar que el usuario inserte valores que no estén repetidos. Para este ejercicio, partimos de la siguiente tabla: Id 1 2 3 4 5 nombre AFRICA EUROPA ASIA OCEANIA RUSIA planeta TIERRA TIERRA TIERRA TIERRA TIERRA La cual fue creada con las siguientes sentencias: create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50) null, planeta nvarchar(50) null); insert into CONTINENTE values('AFRICA', 'TIERRA') insert into CONTINENTE values('EUROPA', 'TIERRA') insert into CONTINENTE values('ASIA', 'TIERRA') insert into CONTINENTE values('OCEANIA', 'TIERRA') insert into CONTINENTE values('RUSIA', 'TIERRA') Queremos impedir que se inserten planetas que no estén incluidos en la tabla y al mismo tiempo impedir que se inserten nombres de continentes que ya existan previamente. Es decir que existen dos condiciones: Condición 1 Impedir que se inserten planetas no incluidos en la tabla “CONTINENTE” Condición 2 Impedir que se inserten nombres de continentes existentes. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 17 Cada una de estas condiciones puede verificarse mediante las instrucciones: Condición 1: Impedir que se inserten planetas no incluidos en la tabla “CONTINENTE” select count(*) from CONTINENTE, inserted where CONTINENTE.planeta like inserted.planeta )=1 Explicación: Cuando se inserta uno que no existe, quiere decir que está en la tabla una sola vez Condición 2 Impedir que se inserten nombres de continentes existentes. select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 Explicación: Cuando se inserta uno que ya existe, está en realidad dos veces Podemos entonces utilizar el operador “OR” para validar si se presenta alguna de estas condiciones, con el ánimo de lograr que el if sea válido. El problema radica cuando ambas condiciones sean ciertas, el “OR” no entra debido a que el “OR” es válido solo cuando alguna es válida, no cuando todas son válidas. Por ello, es necesario agregar una tercera condición: Condición 3: Que se cumplan simultáneamente las dos condiciones. Con todas las explicaciones anteriores, podemos decir que el trigger que realiza el trabajo deseado es algo similar al siguiente: create trigger inserta_continente on CONTINENTE for insert as if (select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 OR (select count(*) from CONTINENTE, inserted where CONTINENTE.planeta like inserted.planeta )=1 OR ((select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 AND (select count(*) from CONTINENTE, inserted where CONTINENTE.planeta like inserted.planeta )=1) begin print "Ya existe este continente:" print "O planeta no existe" Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva select * from inserted print "Por tanto los datos no se insertaron:" rollback transaction select * from CONTINENTE end 18 Con lo cual al ejecutar las siguientes sentencias en el orden especificado a continuación tenemos los siguientes resultados: Sentencia 1 insert into CONTINENTE values('AMERICA DEL NORTE', 'TIERRA') -- BIEN (1 filas afectadas) Sentencia 2 insert into CONTINENTE values('AMERICA DEL NORTE', 'TIERRA1') -- MAL Ya existe este continente: O planeta no existe id 7 nombre AMERICA DEL NORTE planeta TIERRA1 (1 filas afectadas) Por tanto los datos no se insertaron: id nombre planeta 1 AFRICA TIERRA 2 EUROPA TIERRA 3 ASIA TIERRA 4 OCEANIA TIERRA 5 RUSIA TIERRA 6 AMERICA DEL NORTE TIERRA (6 filas afectadas) Sentencia 3 insert into CONTINENTE values('AMERICA DEL NORTE', 'TIERRA') -- MAL Ya existe este continente: O planeta no existe id 8 nombre AMERICA DEL NORTE planeta TIERRA Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 19 (1 filas afectadas) Por tanto los datos no se insertaron: id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA OCEANIA RUSIA AMERICA DEL NORTE planeta TIERRA TIERRA TIERRA TIERRA TIERRA TIERRA (6 filas afectadas) Sentencia 4 insert into CONTINENTE values('AMERICA DEL SUR', 'JUPITER') -- MAL Ya existe este continente: O planeta no existe id 9 nombre AMERICA DEL SUR planeta JUPITER (1 filas afectadas) Por tanto los datos no se insertaron: id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA OCEANIA RUSIA AMERICA DEL NORTE planeta TIERRA TIERRA TIERRA TIERRA TIERRA TIERRA (6 filas afectadas) Sentencia 5 insert into CONTINENTE values('AMERICA DEL SUR', 'TIERRA') -- BIEN (1 filas afectadas) Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 20 Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 21 4. CUARTA UNIDAD: TRIGGERS DE ACTUALIZACIÓN 4.1. CONCEPTUALMENTE COMPRENDIENDO LOS TRIGGERS DE ACTUALIZACION Es importante comprender que los triggers de actualización son una de las cosas mas interesantes en cuanto a triggers se refiere, por cuanto a diferencia de los triggers de inserción, no solamente crean una tabla “inserted”, sino que también crean una tabla “deleted”, en la cual copian los datos que estaban antes de la actualización. Conceptualmente el siguiente diagrama muestra el orden en el que el motor de bases de datos SQL Server ejecuta las instrucciones cuando existen triggers de actualización: Recibe una consulta de actualizacion Verifica si existen triggers de actualizacion NO SI Crea una tabla inserted y otra deleted Copia los datos que se estan en el registro que se quiere actualizar en la tabla deleted Ejecuta la consulta de actualizacion Copia los datos que estan en el registro que se actualizara en la tabla inserted Ejecuta la consulta de actualizacion Ejecuta el trigger de actualizacion Borra las tablas inserted y deleted FIN Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 22 4.2. COLUMNAS ACTUALIZADAS EN UNA ACTUALIZACIÓN A primera vista, el título de este apartado suena un poco confuso, pero en realidad se refiere a la siguiente pregunta: ¿Se actualizó un valor para una columna en una sentencia de actualización? Para comprender mejor esta pregunta, a continuación se muestra la tabla CONTINENTE: Id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA OCEANIA RUSIA AMERICA CENTRAL planeta TIERRA TIERRA TIERRA TIERRA TIERRA TIERRA Creada con las sentencias: create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50) null, planeta nvarchar(50) null); insert into CONTINENTE values('AFRICA', 'TIERRA') insert into CONTINENTE values('EUROPA', 'TIERRA') insert into CONTINENTE values('ASIA', 'TIERRA') insert into CONTINENTE values('OCEANIA', 'TIERRA') insert into CONTINENTE values('RUSIA', 'TIERRA') insert into CONTINENTE values('AMERICA CENTRAL', 'TIERRA') A la cual le asociamos el siguiente trigger de actualización CREATE TRIGGER inserta_continente ON CONTINENTE FOR UPDATE AS IF UPDATE(planeta) PRINT 'La columna PLANETA fue actualizada' Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 23 Ahora bien, para poder entender completamente el trigger, es necesario aclarar que la sentencia: IF UPDATE(planeta) Pregunta si se actualizó la columna “planeta” de la tabla “CONTINENTE”, en caso ser afirmativa la respuesta, se muestra un mensaje y se realiza la actualización. Por ejemplo, al ejecutar la siguiente sentencia: update CONTINENTE set nombre = 'AMERICA' where id = 6 Se produce el siguiente mensaje por parte de SQL Server: (1 filas afectadas) Y la tabla, queda como se muestra a continuación: Id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA OCEANIA RUSIA AMERICA planeta TIERRA TIERRA TIERRA TIERRA TIERRA TIERRA Lo que indica que solamente se actualizó la tabla, pero no se mostró el mensaje, debido a que en la sentencia de actualización no estaba presente el campo “planeta”. Ahora bien, la siguiente sentencia: update CONTINENTE set nombre = 'AMERICA', planeta = 'TIERRA' where id = 6 Produce el siguiente resultado: La columna PLANETA fue actualizada (1 filas afectadas) Y la tabla queda como se muestra a continuación: Id nombre planeta Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 1 2 3 4 5 6 AFRICA EUROPA ASIA OCEANIA RUSIA AMERICA CENTRAL TIERRA TIERRA TIERRA TIERRA TIERRA TIERRA 24 Lo que quiere decir que a pesar de haber actualizado el campo “planeta” con el mismo valor que tenía “TIERRA”, de todas formas, el hecho de haberlo incluido en la sentencia de actualización, de pie para que SQL Server lo tome como un campo modificado. 4.3. TAREA DE INVESTIGACIÓN Para los estudiantes / lectores que deseen utilizar funciones propias de SQL Server, se les sugiere que utilice la función: IF COLUMNS_UPDATED() Para ver que con esta función se logra el mismo efecto que con IF UPDATE(planeta) La tarea consiste en explicar como funciona dicha sentencia. 4.4. TRIGGER DE ACTUALIZACIÓN CONFUSO Dada la tabla CONTINENTE: Id 1 2 3 4 5 6 nombre AFRICA EUROPA ASIA OCEANIA RUSIA AMERICA CENTRAL planeta TIERRA TIERRA TIERRA TIERRA TIERRA TIERRA Creada con las sentencias: Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 25 create table CONTINENTE( --crea la tabla CONTINENTE id int identity(1,1) primary key, nombre nvarchar(50) null, planeta nvarchar(50) null); insert into CONTINENTE values('AFRICA', 'TIERRA') insert into CONTINENTE values('EUROPA', 'TIERRA') insert into CONTINENTE values('ASIA', 'TIERRA') insert into CONTINENTE values('OCEANIA', 'TIERRA') insert into CONTINENTE values('RUSIA', 'TIERRA') insert into CONTINENTE values('AMERICA CENTRAL', 'TIERRA') A la cual le asociamos el siguiente trigger de actualización CREATE TRIGGER inserta_continente ON CONTINENTE FOR UPDATE AS IF UPDATE(planeta) and NOT UPDATE(nombre) PRINT 'La columna PLANETA fue actualizada' rollback PRINT 'Se dehizo la operacion' Las siguientes sentencias producen los siguientes resultados: Sentencias update CONTINENTE set nombre = 'AMERICA' where id = 6 update CONTINENTE set nombre = 'AMERICA', planeta = 'TIERRA' where id = 6 update CONTINENTE set planeta = 'TIERRA' where id = 6 Resultados Se dehizo la operación Se dehizo la operación La columna PLANETA fue actualizada Se dehizo la operación En realidad todas estas operaciones se deshacen, debido básicamente a que lo que se ejecuta dentro del if es la siguiente sentencia. Cosa diferente fuera, si se tuviera definido el trigger así: CREATE TRIGGER inserta_continente ON CONTINENTE FOR UPDATE AS IF UPDATE(planeta) and NOT UPDATE(nombre) BEGIN Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva PRINT 'La columna PLANETA fue actualizada' rollback PRINT 'Se dehizo la operacion' END Tendríamos los siguientes resultados: 26 Sentencias update CONTINENTE set nombre = 'AMERICA' where id = 6 Resultados (1 filas afectadas) update CONTINENTE set nombre = 'AMERICA', planeta = 'TIERRA' where id = 6 (1 filas afectadas) Update CONTINENTE La columna PLANETA fue set planeta = 'TIERRA' actualizada where id = 6 Se dehizo la operacion Tabla CONTINENTE id nombre planeta 1 AFRICA TIERRA 2 EUROPA TIERRA 3 ASIA TIERRA 4 OCEANIA TIERRA 5 RUSIA TIERRA 6 AMERICA TIERRA id nombre planeta 1 AFRICA TIERRA 2 EUROPA TIERRA 3 ASIA TIERRA 4 OCEANIA TIERRA 5 RUSIA TIERRA 6 AMERICA1 TIERRA1 id nombre planeta 1 AFRICA TIERRA 2 EUROPA TIERRA 3 ASIA TIERRA 4 OCEANIA TIERRA 5 RUSIA TIERRA 6 AMERICA1 TIERRA1 Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 27 5. PRIMEROS EJERCICIOS SOBRE TRIGGERS En esta seccion se pretende hacer algunos ejercicios basicos de triggers para lograr que el amigo lector / estudiante adquiera las destrezas y comprenda el funcionamiento de los triggers en SQL Server. 5.1. UN PRIMER EJERCICIO SOBRE TRIGGERS DE ACTUALIZACION Creamos una tabla de la siguiente forma: create table usuario( codigo int, nombre nvarchar(50), edad int ) Insertamos algunos datos: insert into usuario values(1,'Luis Felipe Silva',30) insert into usuario values(2,'Ana Sofia Vergara',30) insert into usuario values(3,'Ana Sofia Henao',30) insert into usuario values(4,'Sofia Cabrales',30) insert into usuario values(5,'Cristina Aguilera',30) Creamos el trigger: create trigger triggeractualizacionusuario on usuario for update as begin select * from usuario select * from inserted select * from deleted end Ejecutamos la consulta: update usuario set nombre='Luis Felipe Wanumen Silva' where codigo=1 La cual produce un resultado similar al siguiente: Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 28 Al ejecutar la consulta en seguida: update usuario set nombre='Luis Felipe Silva' where codigo=1 obtenemos un resultado similar al siguiente: Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 29 Esto nos deja bien en claro que la tabla “inserted” en este tipo de triggers tiene los datos que se van a insertar, que la tabla “deleted” contiene los datos que se van a eliminar y que la tabla “usuario” al interior del trigger tiene los datos actualizados, es decir que primero se ejecuta la consulta de actualización y luego el trigger de actualización. Podemos borrar el trigger usando: drop trigger triggeractualizacionusuario 5.2. UN SEGUNDO EJERCICIO DE TRIGGERS En este segundo ejercicio se pretende hacer un trigger que impida que se actualice un usuario con un código distinto al que tenia este. Creamos una tabla de la siguiente forma: create table usuario( codigo int, nombre nvarchar(50), edad int ) Insertamos algunos datos: insert into usuario values(1,'Luis Felipe Silva',30) insert into usuario values(2,'Ana Sofia Vergara',30) insert into usuario values(3,'Ana Sofia Henao',30) insert into usuario values(4,'Sofia Cabrales',30) insert into usuario values(5,'Cristina Aguilera',30) Creamos el trigger: create trigger triggeractualizacionusuario1 on usuario for update as declare @codigin1 as int declare @codigin2 as int begin select @codigin1 = (select codigo from inserted) select @codigin2 = (select codigo from deleted) if @codigin1 <> @codigin2 rollback transaction end Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 30 Observamos que la tabla usuario contiene los siguientes datos: Codigo 1 2 3 4 5 Nombre Luis Felipe Silva Ana Sofia Vergara Ana Sofia Henao Sofia Cabrales Cristina Aguilera Edad 30 30 30 30 30 Ejecutamos la consulta: update usuario set codigo=7, nombre='Luis Felipe Silva' where codigo=3 y observamos que los datos de la tabla son los siguientes: Codigo 1 2 3 4 5 Nombre Luis Felipe Silva Ana Sofia Vergara Ana Sofia Henao Sofia Cabrales Cristina Aguilera Edad 30 30 30 30 30 Con lo cual vemos que los datos siguen siendo los mismos. Es decir que nuestro trigger de actualización propuesto funciona para el caso en el que se desee actualizar un registro con el código igual al que se tenia. Pensamos: ¿Qué pasaría si hacemos una actualización que no actualice el campo código? update usuario set edad=3, nombre='Natalia Paris' where codigo=3 La respuesta es que la consulta funciona y los datos de la tabla serian como los mostrados a continuación: Codigo 1 2 3 Nombre Luis Felipe Silva Ana Sofia Vergara Natalia Paris Edad 30 30 30 Cuaderno de Triggers Enciclopedia Conociendo Autor: Luis Felipe Wanumen Silva 4 5 Sofia Cabrales Cristina Aguilera 30 30 31 Podemos borrar el trigger usando: drop trigger triggeractualizacionusuario1 5.3. UN TERCER EJERCICIO DE TRIGGERS En esta oportunidad nos proponemos desarrollar un trigger de actualizacion que impida la actualizacion de un registro en su campo nombre por otro que ya exista en la tabla Creamos una tabla de la siguiente forma: create table usuario( codigo int, nombre nvarchar(50), edad int ) Insertamos algunos datos: insert into usuario values(1,'Luis Felipe Silva',30) insert into usuario values(2,'Ana Sofia Vergara',30) insert into usuario values(3,'Ana Sofia Henao',30) insert into usuario values(4,'Sofia Cabrales',30) insert into usuario values(5,'Cristina Aguilera',30) Creamos el trigger: create trigger triggeractualizacionusuario2 on usuario for update as declare @nombrecin1 as nvarchar(50) declare @nombrecin2 as nvarchar(50) declare @codigin1 as int declare @codigin2 as int declare @contador as int begin select @contador = 0 select @nombrecin1 = (select nombre from inserted) select @nombrecin2 = (select nombre from deleted) select @codigin1 = (select codigo from inserted) select @codigin2 = (select codigo from deleted) Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva select @contador = (select count(*) from usuario where nombre=@nombrecin1) if @contador>1 rollback transaction end Ahora para probar el trigger hacemos la siguiente consulta: Antes de probar verificamos que tengamos los siguientes datos en la tabla “usuario”: 32 Codigo 1 2 3 4 5 Nombre Luis Felipe Silva Ana Sofia Vergara Ana Sofia Henao Sofia Cabrales Cristina Aguilera Edad 30 30 30 30 30 Y ahora ejecutamos la siguiente consulta: update usuario set codigo = 20, nombre = 'Luis Felipe' where codigo=2 Con lo cual verificamos que los datos ahora son los siguientes: Codigo 1 20 3 4 5 Nombre Luis Felipe Silva Luis Felipe Ana Sofia Henao Sofia Cabrales Cristina Aguilera Edad 30 30 30 30 30 Esto quiere decir que esta consulta funcion porque esta modificando un nombre “Ana Sofia Vergara” por otro nombre que no existe “Luis Felipe”. Bueno, es probable que el amigo lector diga que si existe otro “Luis Felipe”, pero lo unico cierto es que este primero se llama “Luis Felipe Silva”, en tanto que el que se quiere modificar le falta el “Silva”, recuerde que como no se usan caracteres comodin la palabra tiene que ser exacta. Pero sin mas rodeos hagamos esta otra consulta de actualizacion: update usuario set codigo = 20, nombre = 'Luis Felipe' where codigo=4 Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 33 en donde observamos que los resultados son: Codigo Nombre Edad 1 Luis Felipe Silva 30 20 Luis Felipe 30 3 Ana Sofia Henao 30 4 Sofia Cabrales 30 5 Cristina Aguilera 30 Es decir que los datos no se pudieron cambiar debido a que se deseaba que la persona con el código 4 quedara con el mismo nombre de la persona que actualmente tenia el código 20 y este tipo de cosas dijimos que era precisamente las que el trigger iba a impedir que se realizaran. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 34 6. MAS EJERCICIOS SOBRE TRIGGERS En esta seccion se pretende hacer algunos mas ejercicios de triggers para lograr que el amigo lector / estudiante adquiera las destrezas y comprenda el funcionamiento de los triggers en SQL Server. 6.1. UN TRIGGER DE INSERCION PARA SACAR COPIA El siguiente trigger lo que busca es contar cuantos estudiantes se han ingresado que contengan el mismo numero de codigo en la tabla “estudiante” que el que se esta ingresando y este valor lo coloca en una tabla llamada “copia” que contiene las mismas columnas que la tabla estudiante mas una columna adicional llamada “numero_registros” que contiene el numero de registros que existen con este codigo en la tabla “estudiante”. Esto es bastante util como por ejemplo para hacer una auditoria de cuantos registros existen de cada codigo en la tabla “estudiante” y tener una información actualizada en todo momento de este numero en la tabla “copia”. Para ello se crea primero la tabla “estudiante”: create table estudiante ( codigo int, nombre nvarchar(50), salario int ) Luego la tabla “copia”: create table copia ( codigo int, nombre nvarchar(50), salario int, numero_registros int ) Y se procede a crear el trigger: create trigger actual on estudiante for insert as declare @codigin int declare @nombrecin nvarchar(50) Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva declare @salarin int declare @numero_registros int declare @existe_en_copia int begin set @codigin = (select codigo from inserted) set @nombrecin= (select nombre from inserted) set @salarin = (select salario from inserted) set @numero_registros = (select count(*) from estudiante where codigo = @codigin) set @existe_en_copia = (select count(*) from estudiante where codigo = @codigin) if @existe_en_copia=1 insert into copia values(@codigin,@nombrecin,@salarin,1) else update copia set numero_registros = @existe_en_copia where codigo = @codigin end 35 Observe amigo lector / estudiante que el trigger actua sobre la tabla “estudiante” y solo para las operaciones de inserción en mencionada tabla. De otra parte es bueno notar que los datos que inicialmente son ingresados en la tabla estudiante (Recuerde que primero se ejecuta la inserción y luego el trigger de insercion) son almacenados en tres variables declaradas globalmente que son: @codigin, @nombrecin y @salarin Las cuales son inicializadas al interior del trigger con los valores que se acaban de insertar en la tabla “estudiante”. De otra manera es bueno notar que se cuentan los registros que existen en la tabla “estudiante” que tienen el mismo codigo del que se acaba de ingresar (recuerde que se incluye el que se acabo de ingresar), por esta razon es que si no existe dicho registro en la tabla la variabla “@existe_en_copia” vale “1” si el registro no existia, porque quiere decir que fue el que se acabo de ingresar y como no existia en total existe una sola vez(pues se acaba de ingresar). En el caso que no exista se debe hacer una inserción en la tabla copia con el valor de “1” en el campo “numero_registros”, pero si ya existia, con seguridad ya habia un registro en la tabla “copia” (esto se presupone porque se parte del supuesto que el programador ha creado al trigger antes de hacer incluso la primera inserción en la tabla “estdudiante”). En este ultimo caso, la variable “@existe_en_copia” contiene el numero de veces que existe este registro en la tabla “estudiante”, con lo cual este valor sirve para hacer la actualizacion en la tabla “copia”. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 36 Ahora bien, para lograr comprender el mecanismo de funcionamiento del trigger, se hacen unos ejemplos en los cuales se usa Suponga que ahora se hacen las siguientes inserciones: insert into estudiante values (1, 'Hugo',98) insert into estudiante values (2, 'Paco',98) insert into estudiante values (3, 'Luis',98) Se produce en el analizador de consultas un resultado similar al siguiente: (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) En el cual se puede observer que se han hecho 6 operaciones. Dichas operaciones son de inserción y corresponden a tres inserciones en la tabla “estudiante” y tres inserciones en la tabla “copia”. Al finalizar la ejecución de las consultas y de los triggers asociados con dichas consultas las tablas contienen los siguientes datos: Tabla estudiante: Codigo nombre 1 Hugo 2 Paco 3 Luis Tabla copia: codigo nombre 1 Hugo 2 Paco 3 Luis Salario 98 98 98 salario 98 98 98 numero_registros 1 1 1 En el anterior trigger se puede apreciar que el numero de registros que aparece en ambas tablas es igual y esto es debido a que los datos insertados en la tabla estudiante eran datos de estudiantes con codigos que no existian. A continuación vamos a realizar otras inserciones para probar el funcionamiento del trigger anteriormente elaborado. Para ello, hacemos las siguientes inserciones: insert into estudiante values (1, 'Hugo',98) insert into estudiante values (2, 'Maria',98) insert into estudiante values (5, 'Juan',98) insert into estudiante values (6, 'Elizabeth',98) Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 37 Después de lo cual vemos que ahora los resultados no son iguales en ambas tablas, por cuanto las tablas tienen los siguientes datos ahora: Datos de la tabla “estudiante”: codigo 1 2 3 1 2 5 6 nombre Hugo Paco Luis Hugo Maria Juan Elizabeth salario 98 98 98 98 98 98 98 Datos de la tabla “copia”: codigo 1 2 3 5 6 nombre Hugo Paco Luis Juan Elizabeth salario 98 98 98 98 98 numero_registros 2 2 1 1 1 Las siguientes observaciones se hacen con el fin de explicar detalladamente los resultados anteriores. Observamos que cuando insertamos: insert into estudiante values (1, 'Hugo',98) ya existia este codigo en la tabla “estudiante” y por esto se actualiza el registro en la tabla copia con lo cual queda en la tabla copia: codigo nombre salario numero_registros 1 Hugo 98 2 Observamos que cuando insertamos: insert into estudiante values (2, 'Maria',98) ya existia este codigo en la tabla “estudiante”, pero a diferencia de la anterior actualizacion el campo “nombre” en la tabla copia no queda con el valor adecuado debido a que el trigger solamente tiene en cuenta el campo codigo y no el campo nombre. Observe amigo lector / Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 38 estudiante que el campo nombre no es actualizado en la tabla copia y por tanto el registro en la tabla copia queda asi: codigo 2 nombre Paco salario 98 numero_registros 2 Observamos que cuando insertamos: insert into estudiante values (5, 'Juan',98) insert into estudiante values (6, 'Elizabeth',98) No existian dichos registro en la tabla “estudiante” y por ello se insertan completamente en la tabla “copia” y de paso se les asigna el valor de “1” en el campo “numero_registros” en mencionada tabla. Es decir se insertan los siguientes datos en la tabla “copia”: codigo 5 6 nombre Juan Elizabeth salario 98 98 numero_registros 1 1 Y dado que habia un registro inicialmente en la tabla “estudiante” que no ha sido afectado por ninguna inserción u actualizacion en la tabla “copia”, es bien claro que los registros que deben existir al final de las inserciones en la tabla “copia” deben ser: codigo 1 2 3 5 6 nombre Hugo Paco Luis Juan Elizabeth salario 98 98 98 98 98 numero_registros 2 2 1 1 1 6.2. TRIGGERS PROPUESTOS PARA HACER DE TALLER EN CLASE Con el animo de afianzar los conocimientos adquiridos hasta el momento sobre triggers, se proponen los siguientes triggers para que el amigo lector / estudiante realice a fin de comprender bien el tema de triggers de inserción y de actualizacion. 1. Hacer un trigger que impida que se inserten estudiantes que tengan el mismo nombre Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 39 2. Hacer un trigger que impida que se actualice un registro de un estudiante en su parte codigo de tal forma que dicho codigo quede duplicado en la base de datos 3. Hacer un trigger que impida que se inserte un estudiante con slario mayor a 900 4. Hacer un trigger que impida que se inserte un estudiante con codigo impar 5. Hacer un trigger que impida que se elimine un estudiante que este en la base de datos tres veces, pero si esta una, dos o mas de tres veces si lo deje eliminar. 6. Hacer un trigger que impida que se actualice el nombre de un estudiante, pero si desea actualizar el codigo o el salario o ambos si lo deje actualizar 6.3. UN TRIGGERS INTERRESANTE DE ACTUALIZACION En este ejemplo se pretende hacer un trigger que cuando el usuario intente hacer una actualizacion sobre la tabla estudiante, se permita hacer dicha actualización si el nombre del estudiante por el que se desea actualizar es un nombre que no se encuentra en la lista de estudiantes. En el caso que se desee actualizar el nombre de los estudiantes por uno nombre cuyo contenido ya exista, no se debe permitir dicha actualizacion. 6.4. TRIGGER TALLER PROPUESTO COMO MEJORA AL ANTERIOR Se propone al amigo lector / estudiante mejorar el trigger anterior validando que el usuario no pueda actualizar el código. Esto debido a que el trigger anterior supone que no se realizan actualizaciones sobre el campo código Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 40 7. QUINTA UNIDAD: PROCEDIMIENTOS SOBRE TRIGGERS Para los ejercicios de esta unidad vamos a suponer la tabla “CONTINENTE”: Id 1 2 3 4 5 Nombre AFRICA EUROPA ASIA OCEANIA RUSIA planeta TIERRA TIERRA TIERRA TIERRA TIERRA La cual tiene el siguiente trigger asociado: create trigger inserta_continente on CONTINENTE for insert as if (select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 OR (select count(*) from CONTINENTE, inserted where CONTINENTE.planeta like inserted.planeta )=1 OR ((select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 AND (select count(*) from CONTINENTE, inserted where CONTINENTE.planeta like inserted.planeta )=1) begin print "Ya existe este continente:" print "O planeta no existe" select * from inserted print "Por tanto los datos no se insertaron:" rollback transaction select * from CONTINENTE end 7.1. VER DEPENDENCIAS DE UN TRIGGER Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva El procedimiento almacenado sp_depends permite ver las dependencias de un trigger A manera de ejemplo observemos la siguiente instrucción: sp_depends inserta_continente el cual arroja los siguientes resultados: En la base de datos actual, el objeto especificado hace las siguientes referencias: name dbo.CONTINENTE dbo.CONTINENTE dbo.CONTINENTE type user table user table user table updated no no no selected yes yes yes column id nombre planeta 41 7.2. VER EL TEXTO DE UN TRIGGER El procedimiento almacenado sp_helptext permite ver el texto de un trigger La instrucción: sp_helptext inserta_continente produce el siguiente resultado: Text create trigger inserta_continente on CONTINENTE for insert as if (select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 OR (select count(*) from CONTINENTE, inserted where CONTINENTE.planeta like inserted.planeta )=1 OR Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva ((select count(*) from CONTINENTE, inserted where CONTINENTE.nombre like inserted.nombre)=2 AND (select count(*) from CONTINENTE, inserted where CONTINENTE.planeta like inserted.planeta )=1) begin print "Ya existe este continente:" print "O planeta no existe" select * from inserted print "Por tanto los datos no se insertaron:" rollback transaction select * from CONTINENTE end 42 7.3. VER LOS TRIGGERS EXISTENTES EN UNA TABLA El procedimiento almacenado sp_helptrigger Permite listar los triggers existentes para una determinada tabla. La siguiente instrucción: sp_helptrigger CONTINENTE Produce el siguiente resultado: trigger_name trigger_owner inserta_continente (1 filas afectadas) isupdate dbo isdelete 0 isinsert 0 1 7.4. VER INFORMACIÓN DE UN TRIGGER El procedimiento almacenado: sp_help Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 43 permite mostrar ayuda sobre cualquier objeto en la base de datos, que se encuentre específicamente en la tabla sysobjects. Por ejemplo, la siguiente instrucción: sp_help inserta_continente Muestra información sobre el procedimiento almacenado “inserta_continente”, es decir,muestra los siguientes resultados: Name inserta_continente Owner dbo Type trigger Created_datetime 2003-08-25 18:08:23.570 7.5. VER TRIGGERS CON LA TABLA SYSOBJECTS Recordemos que en la tabla “sysobjects” en SQL Server, se almacena información sobre los diversos objetos existentes en la base de datos, por lo cual es interesante observar que cuando se crea un trigger, se agrega un registro a dicha tabla y se identifica con el nombre “Tr” en la columna “Type” para indicar que se trata de un trigger. Por lo tanto la siguiente consulta: select * from sysobjects where name like 'inserta_continente' and type like 'Tr' Muestra información sobre un trigger denominado “inserta_continente”. Es decir, produce el siguiente resultado(El resultado es mostrado transpuesto, debido a que produce demasiadas columnas y una sola fila, fue necesario transponer el resultado para mostrarlo en forma vertical): Nombre Columna Valor name inserta_continente Id 530100929 xtype TR uid 1 info 0 status 1040 base_schema_ver 0 replinfo 0 parent_obj 498100815 crdate 2003-08-25 18:08:23.570 ftcatid 0 schema_ver 0 stats_schema_ver 0 Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva type userstat sysstat indexdel TR 0 8 0 44 refdate version deltrig instrig updtrig seltrig category cache 2003-08-25 18:08:23.570 0 498100815 0 0 0 0 0 (1 filas afectadas) Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 45 8. TRIGGERS QUE USAN FUNCIONES El uso de triggers, requiere en muchas ocasiones hacer uso de funciones con el fin de resolver ciertas tareas. Es por ello, que se plantea una sección como esta en la que se desarrollan algunos triggers que usan funciones de Transact SQL. 8.1. TRIGGER QUE CALCULA LA LONGUTID DE UN CAMPO Suponga que se crea una tabla ¨ciudadano¨ tal como se muestra a continuación: create table ciudadano( codigo int, nombre nvarchar(50), longitud_del_nombre nvarchar(2) ) Se pretende en este ejercicio que cuando se hagan inserciones como las siguientes: insert into ciudadano(codigo, nombre) values(1,'Luis Felipe') se inserte el siguiente dato: codigo 1 nombre Luis Felipe longitud_del_nombre 11 En pocas palabras se quiere que el trigger inserte los datos del codigo y del nombre del ciudadano que el usuario ha solicitado, pero que el valor que se inserte en el campo “longitud_del_nombre” sea un valor calculado por el trigger e insertado por el mismo con el animo de disminuir la probabilidad de error al hacer inserciones manuales. Observe amigo lector / estudiante que el campo “longitud_del_nombre” contiene un numero que representa el numero de caracteres que contiene el campo “nombre” (incluyendo espacios intermedios) El trigger que realiza la tarea antes expuesta es el siguiente: create trigger triggeractualizacionciudadano on ciudadano for insert as declare @codigin1 as int declare @nombrecin1 as nvarchar(50) declare @longitudin1 as int Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva begin select @codigin1 = (select codigo from inserted) select @nombrecin1 = (select nombre from inserted) select @longitudin1 = (select len(@nombrecin1)) rollback transaction if @longitudin1< 50 insert into ciudadano values(@codigin1,@nombrecin1,@longitudin1) end 46 Recordemos que la tabla “inserted” contiene los datos que el usuario desea insertar en la consulta de inserción SQL. La variable “@nombrecin1” contiene la cadena del nombre que se desea insertar. Dicha cadena es pasada a la funcion “len()” para que esta funcion calcula el numero de caracteres que contiene la cadena y este campo es insertado con la tabla “ciudadano”. Es bueno fijarse que en el caso que el campo tenga una longitud mas grande o igual a 50 no se hacern inserciones. De todas formas es bueno comprender que si el campo tiene 50 caracteres, el motor de bases de datos permite la inserción porque este es el maximo numero de caracteres que se pueden ingresar en el campo “nombre” de la tabla ciudadano, pero si el nombre tiene mas de 50 caracteres, antes que el trigger se ejecute ya el motor ha generado un error similar al siguiente: Servidor: mensaje 8152, nivel 16, estado 4, línea 1 Los datos de cadena o binarios se truncarían. Se terminó la instrucción. Es bueno hacer la siguiente aclaracion que si intentan ejecutar sentencias de inserción como las siguientes: insert into ciudadano values(2,'Luis Felipe Wanumen Silva',34) insert into ciudadano values(3,'Ana Esmeralda',30) se tienen los siguientes datos en la tabla “ciudadano”: codigo 1 2 3 Nombre Luis Felipe Luis Felipe Wanumen Silva Ana Esmeralda longitud_del_nombre 11 25 13 Con lo cual queda bien claro que si intentan ingresar explícitamente datos en el campo “longitud_del_nombre”, dichos datos son ignorados, por cuanto los datos que son ingresados en este campo son los que el trigger calcula. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 47 8.2. TRIGGER QUE INGRESA NOMBRES EN MINUSCULA En algunos casos es interesante observar que si se tiene una tabla como la siguiente: create table ciudadano( codigo int, nombre nvarchar(50) ) Y se hacen las siguientes inserciones: insert into ciudadano values(1,'Luis Felipe') insert into ciudadano values(2,'Ana Esmeralda') insert into ciudadano values(3,'Claudia Bahamon') insert into ciudadano values(4,'Carolina Cruz') insert into ciudadano values(5,'Carolina Sabino') se producen los siguientes resultados: codigo 1 2 3 4 5 nombre Luis Felipe Ana Esmeralda Claudia Bahamon Carolina Cruz Carolina Sabino Lo cual muestra que los nombres que son ingresados en el campo “nombre” de la tabla ciudadano, son los nombres que el usuario ha solicitado su ingreso tal como los ha escrito en la consulta SQL de inserción, teniendo en cuenta si los ingreso con mayúscula o con minúscula. Esto es bien importante de comprender, puesto que en esta sección nos proponemos realizar un trigger que sea capaz de insertar los mismos nombres, pero ahora todos en minúscula, sin importar si la sentencia de inserción por parte del usuario de la base de datos fue con nombres en mayúscula o en minúscula. El trigger que realiza el trabajo anteriormente descrito es el siguiente: create trigger triggeractualizacionciudadano on ciudadano for insert as declare @codigin1 as int declare @nombrecin1 as nvarchar(50) declare @mayuscula_nombre as nvarchar(50) Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva begin select @codigin1 = (select codigo from inserted) select @nombrecin1 = (select nombre from inserted) select @mayuscula_nombre = (select lower(@nombrecin1)) rollback transaction BEGIN TRANSACTION insert into ciudadano values(@codigin1,@mayuscula_nombre) commit end de tal forma que cuando se realiza la inserción siguiente: insert into ciudadano values(1,'Luis Felipe') se obtiene el resultado siguiente: codigo 1 nombre luis felipe 48 Y si se ejecutan una a una las siguientes instrucciones: insert into ciudadano values(2,'Ana Esmeralda') insert into ciudadano values(3,'Claudia Bahamon') insert into ciudadano values(4,'Carolina Cruz') insert into ciudadano values(5,'Carolina Sabino') Se obtiene una tabla con los siguientes datos: codigo 1 2 3 4 5 nombre luis felipe ana esmeralda claudia bahamon carolina cruz carolina sabino En el cual se observa que sin importar si los nombres son ingresados en mayúscula o en minúscula, el trigger convierte todo a minúscula y los inserta en la tabla ciudadano. TAREA PROPUESTA Como tarea le queda al amigo lector / estudiante que explique la razón por la cual no se pueden ejecutar todas las sentencias de inserción al tiempo, porque de hacerse, solamente se efectuaría la inserción del primer registro y los demás no se harían. Es bueno que el Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 49 lector explique por que es necesario en este ejercicio ejecutar las inserciones una a una para que el trigger funcione. 8.3. TRIGGER QUE INGRESA NOMBRES EN MAYUSCULA Supongamos la tabla siguiente: create table ciudadano( codigo int, nombre nvarchar(50) ) Si se realizaren las siguientes inserciones: insert into ciudadano values(1,'Luis Felipe') insert into ciudadano values(2,'Ana Esmeralda') insert into ciudadano values(3,'Claudia Bahamon') insert into ciudadano values(4,'Carolina Cruz') insert into ciudadano values(5,'Carolina Sabino') se tendrian los siguientes resultados: codigo 1 2 3 4 5 Nombre Luis Felipe Ana Esmeralda Claudia Bahamon Carolina Cruz Carolina Sabino Pero lo que se pretende en esta seccion es que cuando se hagan inserciones, dichos nombres ingresados, sean pasados a mayusculas antes de ser insertados definitivamente a la tabla. Esto se puede mediante el siguiente trigger: create trigger triggeractualizacionciudadano on ciudadano for insert as declare @codigin1 as int declare @nombrecin1 as nvarchar(50) declare @minuscula_nombre as nvarchar(50) begin Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva select @codigin1 = (select codigo from inserted) select @nombrecin1 = (select nombre from inserted) select @minuscula_nombre = (select upper(@nombrecin1)) rollback transaction BEGIN TRANSACTION insert into ciudadano values(@codigin1,@minuscula_nombre) commit end de tal forma que cuando se realiza la inserción siguiente: insert into ciudadano values(1,'Luis Felipe') se obtiene el resultado siguiente: codigo 1 nombre Luis Felipe 50 Y si se ejecutan una a una las siguientes instrucciones: insert into ciudadano values(2,'Ana Esmeralda') insert into ciudadano values(3,'Claudia Bahamon') insert into ciudadano values(4,'Carolina Cruz') insert into ciudadano values(5,'Carolina Sabino') Se obtiene una tabla con los siguientes datos: codigo 1 2 3 4 5 nombre LUIS FELIPE ANA ESMERALDA CLAUDIA BAHAMON CAROLINA CRUZ CAROLINA SABINO En el cual se observa que sin importar si los nombres son ingresados en mayúscula o en minúscula, el trigger convierte todo a mayúscula y los inserta en la tabla ciudadano. TAREA PROPUESTA Como tarea le queda al amigo lector / estudiante que explique la razón por la cual no se pueden ejecutar todas las sentencias de inserción al tiempo, porque de hacerse, solamente se efectuaría la inserción del primer registro y los demás no se harían. Es bueno que el lector explique por que es necesario en este ejercicio ejecutar las inserciones una a una para que el trigger funcione. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 51 8.4. TRIGGER QUE INGRESA NOMBRES AL REVES Supongamos la tabla siguiente: create table ciudadano( codigo int, nombre nvarchar(50) ) El siguiente trigger: create trigger triggeractualizacionciudadano on ciudadano for insert as declare @codigin1 as int declare @nombrecin1 as nvarchar(50) declare @nombre_invertido as nvarchar(50) begin select @codigin1 = (select codigo from inserted) select @nombrecin1 = (select nombre from inserted) select @nombre_invertido = (select reverse(@nombrecin1)) rollback transaction BEGIN TRANSACTION insert into ciudadano values(@codigin1,@nombre_invertido) commit end hace que cuando se realicen las siguientes inserciones: insert into ciudadano values(1,'Luis Felipe') insert into ciudadano values(2,'Ana Esmeralda') insert into ciudadano values(3,'Claudia Bahamon') insert into ciudadano values(4,'Carolina Cruz') insert into ciudadano values(5,'Carolina Sabino') se produzcan los siguientes resultados: codigo 1 2 3 nombre epileF siuL adlaremsE anA nomahaB aidualC Cuaderno de Triggers Enciclopedia Conociendo Autor: Luis Felipe Wanumen Silva 4 5 zurC aniloraC onibaS aniloraC 52 8.5. TALLER INVESTIGATIVO Con los anteriores ejercicios fue claro que se pueden usar una serie de funciones para hacer que los triggers hagan ciertas cosas, bien sea ante una inserción, una actualización o una eliminación. En esta sección se deja al amigo lector / estudiante que estudie cada una de las siguientes funciones y sobre cada una de ellas realice triggers de inserción, de actualización y de eliminación a fin que logre comprender no solamente el funcionamiento de los triggers, sino también de las funciones investigadas. 1. Hacer un trigger de actualización en el que se explique el funcionamiento de Asin 2. Hacer un trigger de eliminación en el que se explique el funcionamiento de Asin 3. Hacer un trigger de inserción en el que se explique el funcionamiento de Asin 4. Hacer un trigger de actualización en el que se explique el funcionamiento de Atan 5. Hacer un trigger de eliminación en el que se explique el funcionamiento de Atan 6. Hacer un trigger de inserción en el que se explique el funcionamiento de Atan 7. Hacer un trigger de actualización en el que se explique el funcionamiento de Acos 8. Hacer un trigger de eliminación en el que se explique el funcionamiento de Acos 9. Hacer un trigger de inserción en el que se explique el funcionamiento de Acos 10. Hacer un trigger de actualización en el que se explique el funcionamiento de Patindex 11. Hacer un trigger de eliminación en el que se explique el funcionamiento de Patindex 12. Hacer un trigger de inserción en el que se explique el funcionamiento de Patindex 13. Hacer un trigger de actualización en el que se explique el funcionamiento de Replicate 14. Hacer un trigger de eliminación en el que se explique el funcionamiento de Replicate 15. Hacer un trigger de inserción en el que se explique el funcionamiento de Replicate 16. Hacer un trigger de actualización en el que se explique el funcionamiento de Replace 17. Hacer un trigger de eliminación en el que se explique el funcionamiento de Replace 18. Hacer un trigger de inserción en el que se explique el funcionamiento de Replace 19. Hacer un trigger de actualización en el que se explique el funcionamiento de Rtrim 20. Hacer un trigger de eliminación en el que se explique el funcionamiento de Rtrim 21. Hacer un trigger de inserción en el que se explique el funcionamiento de Rtrim 22. Hacer un trigger de actualización en el que se explique el funcionamiento de Ltrim 23. Hacer un trigger de eliminación en el que se explique el funcionamiento de Ltrim 24. Hacer un trigger de inserción en el que se explique el funcionamiento de Ltrim 25. Hacer un trigger de actualización en el que se explique el funcionamiento de Right 26. Hacer un trigger de eliminación en el que se explique el funcionamiento de Right 27. Hacer un trigger de inserción en el que se explique el funcionamiento de Right 28. Hacer un trigger de actualización en el que se explique el funcionamiento de Left Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 53 29. Hacer un trigger de eliminación en el que se explique el funcionamiento de Left 30. Hacer un trigger de inserción en el que se explique el funcionamiento de Left 31. Hacer un trigger de actualización en el que se explique el funcionamiento de Convert 32. Hacer un trigger de eliminación en el que se explique el funcionamiento de Convert 33. Hacer un trigger de inserción en el que se explique el funcionamiento de Convert 34. Hacer un trigger de actualización en el que se explique el funcionamiento de Charindex 35. Hacer un trigger de eliminación en el que se explique el funcionamiento de Charindex 36. Hacer un trigger de inserción en el que se explique el funcionamiento de Charindex 37. Hacer un trigger de actualización en el que se explique el funcionamiento de Ascii 38. Hacer un trigger de eliminación en el que se explique el funcionamiento de Ascii 39. Hacer un trigger de inserción en el que se explique el funcionamiento de Ascii 40. Hacer un trigger de actualización en el que se explique el funcionamiento de Substring 41. Hacer un trigger de eliminación en el que se explique el funcionamiento de Substring 42. Hacer un trigger de inserción en el que se explique el funcionamiento de Substring Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 54 9. ESPECIFICAR CUANDO ACTIVAR LOS TRIGGERS En las secciones anteriores se ha visto que los triggers se ejecutan por defecto después de realizada la operación de inserción, actualización o eliminación, pero la verdad este comportamiento se puede cambiar y en el momento de creación del trigger se puede especificar en que momento se desea que se ejecute el trigger. 9.1. TRIGGER CON ESPECIFICADOR FOR Supongamos que tenemos la siguiente tabla: create table ciudadano( codigo int, nombre nvarchar(50) ) Y que definimos el siguiente trigger: create trigger triggeractualizacionciudadano on ciudadano for insert as declare @numero_registros as int begin print 'Los registros que hay son ' select @numero_registros = (select count(*) from ciudadano) print @numero_registros select * from ciudadano end Observamos que cuando ejecutamos el trigger se produce Los registros que hay son 1 Codigo nombre 4 Carolina Cruz Lo cual nos deja bien en claro que el trigger se esta ejecutando después de ejecutada la sentencia de inserción. Este comportamiento se presenta por la palabra “for”, la cual le indica al motor de bases de datos que ejecute el trigger después de realizada la sentencia de inserción. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 55 9.2. TRIGGER CON ESPECIFICADOR AFTER Supongamos que tenemos la siguiente tabla: create table ciudadano( codigo int, nombre nvarchar(50) ) Y que definimos el siguiente trigger: create trigger triggeractualizacionciudadano on ciudadano after insert as declare @numero_registros as int begin print 'Los registros que hay son ' select @numero_registros = (select count(*) from ciudadano) print @numero_registros select * from ciudadano end Observamos que cuando ejecutamos el trigger se produce Los registros que hay son 1 Codigo nombre 4 Carolina Cruz Lo cual nos deja comprender que al igual que el trigger de la sección anterior, este trigger se ejecuta después de ejecutadas las instrucciones de inserción. En pocas términos podemos afirmar que tanto las palabras “for’ como “after” le indican al motor que ejecute el trigger después de ejecutadas las instrucciones. Este tipo de cosas es bueno tenerlas en cuenta. NOTA: El numero de triggers que una tabla puede tener del tipo “for’ o “after” pueden ser varios. Bueno, eso si, teniendo en cuenta que un trigger de pronto no invoque a otro y entonces tendríamos una invocación infinita de triggers, lo que desembocaría en un colapso de la base de datos en un momento dado. Esta restricción también aplica no solo para tablas, sino para vistas. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 56 9.3. TRIGGER CON ESPECIFICADOR INSTEAD OF Supongamos que tenemos la siguiente tabla: create table ciudadano( codigo int, nombre nvarchar(50) ) Y que definimos el siguiente trigger: create trigger triggeractualizacionciudadano on ciudadano instead of insert as declare @numero_registros as int begin print 'Los registros que hay son ' select @numero_registros = (select count(*) from ciudadano) print @numero_registros select * from ciudadano end Observamos que cuando ejecutamos el trigger se produce Los registros que hay son 0 Codigo Nombre Con lo cual podemos afirmar que cuando se ejecuto el trigger todavía no se había ejecutado la instrucción de inserción. NOTA: El numero de triggers que una tabla puede tener del tipo “instead of’ puede ser máximo de uno por cada tipo de acción. (Las acciones pueden ser: update, inserted, deleted). Esta restricción también aplica no solo para tablas, sino para vistas. Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 57 TABLA DE CONTENIDO 1. PRIMERA UNIDAD: INTRODUCCIÓN A LOS TRIGGERS ___________________ 3 1.1. DEFINICIÓN ______________________________________________________ 3 1.2. OBJETIVO DE LOS TRIGGERS _______________________________________ 3 1.3. CONSIDERACIONES SOBRE TRIGGERS ______________________________ 3 2. SEGUNDA UNIDAD: TRIGGERS Y MAS CONCEPTOS BASICOS _____________ 4 2.1. UN TRIGGER SIEMPRE SE BORRA CUANDO SE BORRA LA TABLA ASOCIADA ___________________________________________________________ 4 2.2. UN TRIGGER DEBE SER LA PRIMERA SENTENCIA EN ARCHIVO DE LOTES _______________________________________________________________ 5 2.3. MENSAJES EN LA INSERCIÓN ______________________________________ 7 2.4. MENSAJES EN LA ACTUALIZACIÓN _________________________________ 8 2.5. MENSAJES EN EL BORRADO DE REGISTROS _________________________ 9 3. TERCERA UNIDAD: TRIGGERS DE INSERCIÓN __________________________ 11 3.1. LA TABLA INSERTED _____________________________________________ 11 3.2. INSERCIÓN CONDICIONAL ________________________________________ 13 3.3. ORDEN DE EJECUCIÓN CON TRIGGERS ____________________________ 15 3.4. IMPIDIENDO VALORES NO EXISTENTES ___________________________ 16 4. CUARTA UNIDAD: TRIGGERS DE ACTUALIZACIÓN _____________________ 21 4.1. CONCEPTUALMENTE COMPRENDIENDO LOS TRIGGERS DE ACTUALIZACION ____________________________________________________ 21 4.2. COLUMNAS ACTUALIZADAS EN UNA ACTUALIZACIÓN _____________ 22 4.3. TAREA DE INVESTIGACIÓN _______________________________________ 24 4.4. TRIGGER DE ACTUALIZACIÓN CONFUSO __________________________ 24 5. PRIMEROS EJERCICIOS SOBRE TRIGGERS______________________________ 27 5.1. UN PRIMER EJERCICIO SOBRE TRIGGERS DE ACTUALIZACION ______ 27 5.2. UN SEGUNDO EJERCICIO DE TRIGGERS ____________________________ 29 5.3. UN TERCER EJERCICIO DE TRIGGERS ______________________________ 31 6. MAS EJERCICIOS SOBRE TRIGGERS ___________________________________ 34 6.1. UN TRIGGER DE INSERCION PARA SACAR COPIA ___________________ 34 6.2. TRIGGERS PROPUESTOS PARA HACER DE TALLER EN CLASE ________ 38 6.3. UN TRIGGERS INTERRESANTE DE ACTUALIZACION ________________ 39 6.4. TRIGGER TALLER PROPUESTO COMO MEJORA AL ANTERIOR _______ 39 7. QUINTA UNIDAD: PROCEDIMIENTOS SOBRE TRIGGERS _________________ 40 7.1. VER DEPENDENCIAS DE UN TRIGGER______________________________ 40 7.2. VER EL TEXTO DE UN TRIGGER ___________________________________ 41 7.3. VER LOS TRIGGERS EXISTENTES EN UNA TABLA ___________________ 42 7.4. VER INFORMACIÓN DE UN TRIGGER_______________________________ 42 7.5. VER TRIGGERS CON LA TABLA SYSOBJECTS _______________________ 43 8. TRIGGERS QUE USAN FUNCIONES ____________________________________ 45 8.1. TRIGGER QUE CALCULA LA LONGUTID DE UN CAMPO _____________ 45 8.2. TRIGGER QUE INGRESA NOMBRES EN MINUSCULA _________________ 47 Enciclopedia Conociendo Cuaderno de Triggers Autor: Luis Felipe Wanumen Silva 58 49 51 52 54 54 55 56 57 8.3. TRIGGER QUE INGRESA NOMBRES EN MAYUSCULA ________________ 8.4. TRIGGER QUE INGRESA NOMBRES AL REVES ______________________ 8.5. TALLER INVESTIGATIVO _________________________________________ 9. ESPECIFICAR CUANDO ACTIVAR LOS TRIGGERS _______________________ 9.1. TRIGGER CON ESPECIFICADOR FOR _______________________________ 9.2. TRIGGER CON ESPECIFICADOR AFTER _____________________________ 9.3. TRIGGER CON ESPECIFICADOR INSTEAD OF _______________________ TABLA DE CONTENIDO ________________________________________________ Enciclopedia Conociendo Cuaderno de Triggers