tutorial trigger tipos son que los implementan estructura donde crean condiciones como sql sql-server tsql triggers

trigger - Disparadores SQL: ¿cómo obtengo el valor actualizado?



trigger en sql server 2014 (3)

¿Cómo obtengo el valor del registro actualizado en un desencadenador SQL? Algo como esto:

CREATE TRIGGER TR_UpdateNew ON Users AFTER UPDATE AS BEGIN SET NOCOUNT ON; EXEC UpdateProfile (SELECT UserId FROM updated AS U); END GO

Obviamente esto no funciona, pero pueden ver a lo que intento llegar.


Puede hacer algo como este ejemplo en el que estoy registrando cambios en una tabla de historial de transacciones:

create table dbo.action ( id int not null primary key , description varchar(32) not null unique , ) go insert dbo.action values( 1 , ''insert'' ) insert dbo.action values( 2 , ''update'' ) insert dbo.action values( 3 , ''delete'' ) go create table dbo.foo ( id int not null identity(1,1) primary key , value varchar(200) not null unique , ) go create table dbo.foo_history ( id int not null , seq int not null identity(1,1) , action_date datetime not null default(current_timestamp) , action_id int not null foreign key references dbo.action ( id ), old_value varchar(200) null , new_value varchar(200) null , primary key nonclustered ( id , seq ) , ) go create trigger foo_update_01 on dbo.foo for insert, update , delete as set nocount on set xact_abort on set ansi_nulls on set concat_null_yields_null on -- -- record change history -- insert dbo.foo_history ( id , action_id , old_value , new_value ) select id = coalesce( i.id , d.id ) , action_id = case when i.id is not null and d.id is null then 1 -- insert when i.id is not null and d.id is not null then 2 -- update when i.id is null and d.id is not null then 3 -- delete end , old_value = d.value , new_value = i.value from inserted i full join deleted d on d.id = i.id go

Pero puede usar el mismo tipo de técnica, mezclarlo un poco y pasar todo el conjunto de valores a un procedimiento almacenado, como hago en el siguiente ejemplo (usando el esquema de la tabla anterior).

Primero, cree un procedimiento almacenado que espera que exista una tabla temporal particular en tiempo de ejecución, por lo tanto:

-- -- temp table must exist or the stored procedure won''t compile -- create table #foo_changes ( id int not null primary key clustered , action_id int not null , old_value varchar(200) null , new_value varchar(200) null , ) go -- -- create the stored procedure -- create procedure dbo.foo_changed as -- -- do something useful involving the contents of #foo_changes here -- select * from #foo_changes return 0 go -- -- drop the temp table -- drop table #foo_changes go

Una vez que haya hecho eso, cree un disparador que creará y rellenará la tabla temporal que espera el procedimiento almacenado y luego ejecutará el procedimiento almacenado:

create trigger foo_trigger_01 on dbo.foo for insert, update , delete as set nocount on set xact_abort on set ansi_nulls on set concat_null_yields_null on -- -- create the temp table. This temp table will be in scope for any stored -- procedure executed by this trigger. It will be automagickally dropped -- when trigger execution is complete. -- -- Any changes made to this table by a stored procedure — inserts, -- deletes or updates are, of course, visible to the trigger upon return -- from the stored procedure. -- create table #foo_changes ( id int not null primary key clustered , action_id int not null , old_value varchar(200) null , new_value varchar(200) null , ) -- -- populate the temp table -- insert #foo_changes ( id , action_id , old_value , new_value ) select id = coalesce( i.id , d.id ) , action_id = case when i.id is not null and d.id is null then 1 -- insert when i.id is not null and d.id is not null then 2 -- update when i.id is null and d.id is not null then 3 -- delete end , old_value = d.value , new_value = i.value from inserted i full join deleted d on d.id = i.id -- -- execute the stored procedure. The temp table created above is in scope -- for the stored procedure, so it''s able to access the set of changes from -- the trigger. -- exec dbo.foo_changed go

Eso es todo lo que hay para eso. Es simple, es fácil, funciona para conjuntos de cambios de cualquier tamaño. Y es seguro, sin condiciones de carrera o colisiones con otros usuarios en el sistema.


Según mis conocimientos, necesitaría crear un CURSOR para recorrer todos los valores actualizados y ejecutar el procedimiento UpdateProfile. Tenga en cuenta que esto ralentizará su proceso de actualización.

Declare @UserID int --Assuming Declare UpdateProfile_Cursor Cursor for Select UserID From inserted; Open Cursor UpdateProfile_Cursor; Fetch Next from UpdateProfile_Cursor Into @UserID; While @@FETCH_STATUS == 0 Begin Exec UpdateProfile @UserID Fetch Next from UpdateProfile_Cursor Into @UserID; End CLOSE UpdateProfile_Cursor DEALLOCATE UpdateProfile_Cursor

Mi sintaxis puede estar un poco desajustada, pero esto te dará el efecto deseado. Nuevamente, considere revisar su lógica para manejar múltiples actualizaciones ya que el uso de cursores consume muchos recursos.


Siempre que esté seguro de que solo se actualizará un solo valor, puede hacerlo ...

CREATE TRIGGER TR_UpdateNew ON Users AFTER UPDATE AS BEGIN SET NOCOUNT ON; DECLARE @user_id INT SELECT @user_id = inserted.UserID FROM inserted INNER JOIN deleted ON inserted.PrimaryKey = deleted.PrimaryKey -- It''s an update if the record is in BOTH inserted AND deleted EXEC UpdateProfile @user_id; END GO

Si se pueden actualizar varios valores a la vez, solo uno de ellos será procesado por este código. (Aunque no va a error.)

Podría usar un cursor, o si es SQL Server 2008+ puede usar variables de tabla.

O, más comúnmente, simplemente mueva el código StoredProcedure al disparador.