2011-10-17 17 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

私の知識に基づいて、UpdateProfileプロシージャを実行するために更新されたすべての値をループするCURSORを作成する必要があります。これにより、更新プロセスが遅くなることに注意してください。

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 

これはすべてです。シンプルで簡単ですが、どのサイズのチェンジセットでも機能します。また、競合状態やシステム内の他のユーザーとの衝突もなく、安全です。

関連する問題