Trigger SQL Server



¿Que es un trigger?

Un trigger (disparador) es un objeto que se encuentra ligado a una tabla el cual se ejecuta después de un evento que sucede en la tabla, las cuales son: INSERT, UPDATE, DELETE. Esto significa que al suceder la acción en la tabla automáticamente se ejecuta el trigger el cual puede tener una o varias instrucciones a proceder.

Ventajas

  • Provee una alternativa para la verificación de la integridad en los datos.
  • Puede detectar errores en la lógica de negocio en la base de datos.
  • Se puede utilizar como tareas programadas (Task Schedule).
  • Útiles para auditar los cambios en las bases de datos.

Desventajas

  • Pueden aumentar la sobrecarga del servidor de base de datos.
  • Se ejecutan y son invisibles desde las aplicaciones cliente, por lo tanto, es difícil averiguar qué sucede en la capa de base de datos.

Sintaxis de creación, modificación y eliminado de triggers.

Crear:

CREATE TRIGGER <Nombre>
ON <NombreTabla>
AFTER <Evento>
AS

Modificar:

ALTER TRIGGER <Nombre>
ON <NombreTabla>
AFTER <Evento>
AS

Borrar:

DROP TRIGGER <Nombre>

Tablas de eventos en triggers


Al crear los triggers se ejecutan después de afectar los eventos en las tablas, SQL Server crear tablas por evento para indicar cuales fueron los valores que se utilizaron a ejecutar el trigger y podemos acceder a estos en las tablas: INSERTED, DELETED, al actualizar la tabla (UPDATE), los datos se encuentran en la tabla INSERTED.

Ejemplos:

Query para el siguiente ejemplo, tabla Personas e historial de nombre.

CREATE TABLE Personas(
       PersId int PRIMARY KEY IDENTITY(1,1) NOT NULL,
       PersNombre nvarchar (80) NOT NULL,
       PersFecNacimiento datetime NULL,
       PersActivo bit NOT NULL
       )

CREATE TABLE HistorialNombresPersonas
(
Id Int IDENTITY Primary Key
PersId INT,
ValorAnterior Nvarchar(80),
ValorNuevo Nvarchar(80)
)

Para el siguiente ejemplo, se va almacenar todos los cambios realizados en la columna nombre de la tabla Personas.

CREATE TRIGGER TR_HistoNombre
ON dbo.Personas
AFTER UPDATE
AS
       DECLARE @Id INT
       SET @Id = (SELECT PersId FROM INSERTED)

       DECLARE @NombreNuevo NVARCHAR(80)
       SET @NombreNuevo = (SELECT PersNombre FROM INSERTED)

       DECLARE @NombreAnterior NVARCHAR(80)
       SET @NombreAnterior = (SELECT PersNombre FROM DELETED)

       INSERT INTO HistorialNombresPersonas
       VALUES (@Id,@NombreAnterior,@NombreNuevo)

El trigger anterior funciona correctamente sí nos aseguramos que siempre se va a actualizar registro por registro. Las tablas INSERTED y DELETED pueden contener más de una fila, al ejecutar el UPDATE en más de un registro en la tabla; sobre el trigger ocurre la excepción y los cambios no se ven afectados. Ejemplo de query que provoca el error al actualizar en la tabla:

UPDATE Personas SET
       PersNombre = 'Nuevo Nombre'


ALTER TRIGGER TR_HistoNombre
ON Personas
AFTER UPDATE
AS
       INSERT INTO HistorialNombresPersonas
       SELECT INSERTED.PersId, DELETED.PersNombre, INSERTED.PersNombre
       FROM INSERTED
       INNER JOIN DELETED ON INSERTED.PersId = DELETED.PersId

Modificación del trigger para actualizar más de una fila a la vez, al ejecutarse inserta los nombres correctamente en la tabla HistorialNombresPersonas, aun así, este trigger se ejecuta al actualizar cualquier columna de la tabla Persona, en este ejemplo puede funcionar, pero estaría acumulando los nombres cuando realmente no sufrió un cambio. Ejemplo sí en la tabla Persona se actualiza el campo PersFecNacimiento, se dispara el trigger y almacena en la tabla HistorialNombresPersonas y procede a guardar un registro con el mismo nombre en los campos ValorAnterior y ValorNuevo.

En la siguiente alteración del trigger se corrige el problema anterior validando dentro de la operación del trigger que, si la columna PersNombre es la afectada, se procede a crear el registro en la tabla HistorialNombresPersonas.

ALTER TRIGGER TR_HistoNombre
ON Personas
AFTER UPDATE
AS
       IF UPDATE (PersNombre)
       BEGIN
              INSERT INTO HistorialNombresPersonas
              SELECT INSERTED.PersId, DELETED.PersNombre, INSERTED.PersNombre
              FROM INSERTED
              INNER JOIN DELETED ON INSERTED.PersId = DELETED.PersId
       END

Hasta esta alteración del trigger funciona correctamente, pero aún se tiene un detalle que el cual queda a criterio de cómo se quiere manejar. El detalle pasa cuando se actualiza la columna PersNombre con el mismo valor que tiene anteriormente.

UPDATE Personas SET
       PersNombre = PersNombre
       WHERE Personas.PersId = 1

Este query actualiza la columna PersNombre con el mismo valor, el cual genera un registro en la tabla HistorialNombresPersonas, esto pasa porque cumple con todos los filtros que tiene el trigger, sí se requiere guardar un registro con el mismo valor en las columnas, se debe agregar un filtro para que no se genere el registro.

ALTER TRIGGER TR_HistoNombre
ON Personas
AFTER UPDATE
AS
       IF UPDATE (PersNombre)
       BEGIN
              INSERT INTO HistorialNombresPersonas
              SELECT INSERTED.PersId, DELETED.PersNombre, INSERTED.PersNombre
              FROM INSERTED
              INNER JOIN DELETED ON INSERTED.PersId = DELETED.PersId
              WHERE DELETED.PersNombre <> INSERTED.PersNombre
       END

Con el filtro WHERE queda listo para que no genere registro con el mismo valor en ambas columnas.


Sigue este Blog desde Telegram: Clic aquí para unirte al canal

Compartir
Compartir

Comments

Week's Hit

Jobs SQL Server P1

Funciones SQL Server