2011-10-17 14 views
5

Come faccio ad avere il valore del record aggiornato in un trigger SQL - qualcosa di simile:Trigger SQL: come ottengo il valore aggiornato?

CREATE TRIGGER TR_UpdateNew 
    ON Users 
    AFTER UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON; 

    EXEC UpdateProfile (SELECT UserId FROM updated AS U); 

END 
GO 

Ovviamente questo non funziona, ma si può vedere quello che sto cercando di arrivare.

risposta

9

Fornire si è certi che un solo valore sarà mai aggiornato, si può fare questo ...

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 

Se più valori possono essere aggiornati in una sola volta, solo uno di loro sarà ottenere elaborati da questo codice (Anche se non errore.)

È possibile utilizzare un cursore o se è SQL Server 2008+ è possibile utilizzare variabili di tabella.

Oppure, più comunemente, basta spostare il codice StoredProcedure nel trigger.

1

Sulla base delle mie conoscenze, è necessario creare un CURSORE per scorrere tutti i valori aggiornati per eseguire la procedura UpdateProfile. Tieni presente che questo rallenterà la tua procedura di aggiornamento.

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 

La mia sintassi può essere un po 'spenta, ma questo ti darà l'effetto desiderato. Ancora una volta, si consideri la revisione della logica per gestire più aggiornamenti poiché l'utilizzo di cursori richiede un uso intensivo delle risorse.

0

Si può fare qualcosa di simile esempio in cui sto accedendo modifiche a una tabella cronologia delle transazioni:

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 

Ma è possibile utilizzare lo stesso tipo di tecnica, mescolare un po 'e passare l'intero set di valori ad una stored procedure, come faccio nel seguente esempio (usando lo schema della tabella sopra).

In primo luogo, creare una stored procedure che prevede una particolare tabella temporanea di esistere in fase di esecuzione, in tal modo:

-- 
-- 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 volta fatto questo, creare un trigger che creerà e popolare la tabella temporanea previsto dalla la stored procedure e quindi eseguire la stored procedure:

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 

questo è tutto quello che c'è da fare. È semplice, è facile, funziona per serie di modifiche di qualsiasi dimensione. E, è sicuro, senza condizioni di gara o collisioni con altri utenti nel sistema.

Problemi correlati