2011-10-17 38 views
5

我要如何在SQL觸發器更新的記錄的價值 - 是這樣的:SQL觸發器 - 如何獲取更新的值?

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

    EXEC UpdateProfile (SELECT UserId FROM updated AS U); 

END 
GO 

顯然,這是不行的,但你可以看到什麼,我想要知道的。

回答

9

提供你一定只有一個值永遠不會被更新,你可以做到這一點...

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 

如果有多個值可以一次更新,只是其中之一將得到處理這段代碼。 (儘管它不會出錯。)

您可以使用遊標,或者如果它是SQL Server 2008+,則可以使用表變量。

或者更常見的,只是將StoredProcedure代碼移入觸發器。

1

根據我的知識,您需要創建一個CURSOR來遍歷所有更新的值以執行UpdateProfile過程。請記住,這會減慢更新過程。

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 

我的語法可能有點偏離,但這會給你想要的效果。再次考慮修改你的邏輯來處理多個更新,因爲使用遊標是資源密集型的。

0

你可以這樣做例子,我記錄更改爲交易歷史記錄表:

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 

但是你可以使用相同的排序技術,它有點混合起來,並通過整個集合的值存儲到存儲過程中,就像我在下面的示例中所做的(使用上面的表格模式)。

首先,創建一個存儲過程需要一個特殊的臨時表在運行時存在,因此:

-- 
-- 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 

一旦你做到了這一點,創建一個觸發器,它會創建並填充由預計的臨時表存儲過程,然後執行存儲過程:

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 

這是對所有有它。它很簡單,很容易,適用於任何尺寸的變化套件。而且,它是安全的,沒有競爭條件或與系統中的其他用戶發生衝突。