26 de enero de 2015

Triggers en SQL

Ejemplo utilizando la table INSERTED

CREATE TRIGGER TR_CUENTAS
ON CUENTAS
AFTER UPDATE

AS

BEGIN
-- SET NOCOUNT ON impide que se generen mensajes de texto
-- con cada instrucción
SET NOCOUNT ON;
INSERT INTO HCO_SALDOS
(IDCUENTA, SALDO, FXSALDO)
SELECT IDCUENTA, SALDO, getdate()
FROM INSERTED
END

Ejemplo utilizando dos tablas, una de ellas es la tabla INSERTED

USE Blogger
    GO

    CREATE TRIGGER ActualizaVentasEmpleados
    ON pedidos FOR INSERT

    AS

    UPDATE  empleados SET ventas=ventas+inserted.importe
    FROM  empleados, inserted
    WHERE  numemp=inserted.rep;

    GO

Una consideración a tener en cuenta es que el trigger se ejecutará aunque la instruccion DML (UPDATE, INSERT o DELETE ) no haya afectado a ninguna fila. En este caso inserted y deleted devolverán un conjunto de datos vacío.

Podemos especificar a que columnas de la tabla debe afectar el trigger.

ALTER TRIGGER TR_CUENTAS
ON CUENTAS
AFTER UPDATE

AS
BEGIN
-- SET NOCOUNT ON impide que se generen mensajes de texto
-- con cada instrucción
SET NOCOUNT ON;

IF UPDATE(SALDO) -- Solo si se actualiza SALDO
BEGIN
INSERT INTO HCO_SALDOS
(IDCUENTA, SALDO, FXSALDO)
SELECT IDCUENTA, SALDO, getdate()
FROM INSERTED
END
END

 Los trigger están dentro de la transacción original (Insert, Delete o Update) por lo cual si dentro de nuestro trigger hacemos un RollBack Tran, no solo estaremos echando atrás nuestro trigger sino también toda la transacción; en otras palabras si en un trigger ponemos un RollBack Tran, la transacción de Insert, Delete o Update volverá toda hacia atrás.

ALTER TRIGGER TR_CUENTAS
ON CUENTAS
AFTER UPDATE

AS
BEGIN
-- SET NOCOUNT ON impide que se generen mensajes de texto
-- con cada instrucción
SET NOCOUNT ON;
INSERT INTO HCO_SALDOS
(IDCUENTA, SALDO, FXSALDO)
SELECT IDCUENTA, SALDO, getdate()
FROM INSERTED

ROLLBACK
END

En este caso obtendremos el siguiente mensaje de error:
La transacción terminó en el desencadenador. Se anuló el lote.

Ejemplo de After Insert

CREATE TRIGGER trgAfterInsert ON [dbo].[Employee_Test]
FOR INSERT
AS
       declare @empid int;
       declare @empname varchar(100);
       declare @empsal decimal(10,2);
       declare @audit_action varchar(100);

       select @empid=i.Emp_ID from inserted i;
       select @empname=i.Emp_Name from inserted i;   
       select @empsal=i.Emp_Sal from inserted i;     
       set @audit_action='Inserted Record -- After Insert Trigger.';

       insert into Employee_Test_Audit
           (Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
       values(@empid,@empname,@empsal,@audit_action,getdate());

       PRINT 'AFTER INSERT trigger fired.'
GO


Ejemplo de After Update

CREATE TRIGGER trgAfterUpdate ON [dbo].[Employee_Test]
FOR UPDATE
AS
       declare @empid int;
       declare @empname varchar(100);
       declare @empsal decimal(10,2);
       declare @audit_action varchar(100);

       select @empid=i.Emp_ID from inserted i;
       select @empname=i.Emp_Name from inserted i;   
       select @empsal=i.Emp_Sal from inserted i;     
      
       if update(Emp_Name)
             set @audit_action='Updated Record -- After Update Trigger.';
       if update(Emp_Sal)
             set @audit_action='Updated Record -- After Update Trigger.';

       insert into Employee_Test_Audit(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
       values(@empid,@empname,@empsal,@audit_action,getdate());

       PRINT 'AFTER UPDATE Trigger fired.'
GO


Ejemplo de After Delete

CREATE TRIGGER trgAfterDelete ON [dbo].[Employee_Test]
AFTER DELETE
AS
       declare @empid int;
       declare @empname varchar(100);
       declare @empsal decimal(10,2);
       declare @audit_action varchar(100);

       select @empid=d.Emp_ID from deleted d; 
       select @empname=d.Emp_Name from deleted d;    
       select @empsal=d.Emp_Sal from deleted d;
       set @audit_action='Deleted -- After Delete Trigger.';

       insert into Employee_Test_Audit
(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
       values(@empid,@empname,@empsal,@audit_action,getdate());

       PRINT 'AFTER DELETE TRIGGER fired.'
GO


Ejemplo Instead Of

CREATE TRIGGER trgInsteadOfDelete ON [dbo].[Employee_Test]
INSTEAD OF DELETE
AS
       declare @emp_id int;
       declare @emp_name varchar(100);
       declare @emp_sal int;
      
       select @emp_id=d.Emp_ID from deleted d;
       select @emp_name=d.Emp_Name from deleted d;
       select @emp_sal=d.Emp_Sal from deleted d;

       BEGIN
             if(@emp_sal>1200)
             begin
                    RAISERROR('Cannot delete where salary > 1200',16,1);
                    ROLLBACK;
             end
             else
             begin
                    delete from Employee_Test where Emp_ID=@emp_id;
                    COMMIT;
             insert into Employee_Test_Audit(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
                    values(@emp_id,@emp_name,@emp_sal,'Deleted -- Instead Of Delete Trigger.',getdate());
                    PRINT 'Record Deleted -- Instead Of Delete Trigger.'
             end
       END
GO


Otro ejemplo de trigger Instead Of

create TRIGGER actualizar
    on usuarios
    Instead Of update
    AS
        IF update (descripcion)
        BEGIN
    SET NOCOUNT ON;
            RAISERROR ('Imposible actualizar los registros',16, 1)
    ROLLBACK TRAN
        END
 


Trigger DDL
Los trigger DDL se ejecutan en respuesta a una variedad de eventos de lenguaje de definición de datos (DDL). Estos eventos corresponden principalmente a instrucciones CREATE, ALTER y DROP de Transact-SQL, y a determinados procedimientos almacenados del sistema que ejecutan operaciones de tipo DDL.
La siguiente instrucción impide que se ejecuten sentencias DROP TABLE y ALTER TABLE en la base de datos.
CREATE TRIGGER TR_SEGURIDAD
ON DATABASE FOR DROP_TABLE, ALTER_TABLE
AS
BEGIN
RAISERROR ('No está permitido borrar ni modificar tablas !' , 16, 1)
ROLLBACK TRANSACTION
END

Otro ejemplo
CREATE TRIGGER SEGURIDAD
    ON DATABASE FOR Create_table,DROP_TABLE, ALTER_TABLE
    AS
    BEGIN
   RAISERROR ('Imposible crear, borrar ni modificar tablas,Faltan permisos' , 16, 1)
    ROLLBACK TRANSACTION
    INSERT Auditoria VALUES ('','',GetDate())
    END

Deshabilitar Triggers

En ocasiones puede ser útil inhabilitar temporalmente un desencadenador sin que por ello suponga eliminarlo, para estos casos podemos utilizar la sentencia DISABLE TRIGGER.

Ejemplo:

DISABLE TRIGGER  ActualizaVentasEmpleado ON pedidos;

Deshabilita todos los desencadenadores asociados a la tabla pedidos.
DISABLE TRIGGER ALL ON pedidos;
   
Deshabilita todos los desencadenadores definidos en la base de datos actual.
DISABLE TRIGGER ALL ON DATABASE; 

Deshabilita todos los desencadenadores definidos en el servidor.
DISABLE TRIGGER ALL ON ALL SERVER;