2011-10-17 30 views
5

Làm thế nào để có được giá trị của hồ sơ được cập nhật trong một kích hoạt SQL - một cái gì đó như thế này:Trình kích hoạt SQL - làm cách nào để nhận giá trị được cập nhật?

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

    EXEC UpdateProfile (SELECT UserId FROM updated AS U); 

END 
GO 

Rõ ràng điều này không làm việc, nhưng bạn có thể thấy những gì tôi đang cố gắng để có được ít.

Trả lời

9

Cung cấp bạn nhất định rằng chỉ có một giá trị sẽ bao giờ được cập nhật, bạn có thể làm điều này ...

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 

Nếu có nhiều giá trị có thể được cập nhật cùng một lúc, chỉ một trong số họ sẽ được xử lý bởi mã này. (Mặc dù nó không lỗi.)

Bạn có thể sử dụng con trỏ, hoặc nếu đó là SQL Server 2008+ bạn có thể sử dụng các biến bảng.

Hoặc, thông thường hơn, chỉ cần di chuyển mã StoredProcedure vào trình kích hoạt.

1

Dựa trên kiến ​​thức của tôi, bạn cần phải tạo một CURSOR để lặp qua tất cả các giá trị được cập nhật để thực thi thủ tục UpdateProfile. Hãy ghi nhớ điều này sẽ làm chậm quá trình cập nhật của bạ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 

Cú pháp của tôi có thể hơi lệch nhưng điều này sẽ mang đến cho bạn hiệu quả mong muốn. Một lần nữa, hãy xem xét sửa đổi logic của bạn để xử lý nhiều bản cập nhật khi sử dụng con trỏ là tài nguyên chuyên sâu.

0

Bạn có thể làm một cái gì đó giống như ví dụ này, nơi tôi đang đăng nhập thay đổi cho một bảng lịch sử giao dịch:

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 

Nhưng bạn có thể sử dụng cùng một loại kỹ thuật, pha trộn nó lên một chút và vượt qua toàn bộ bộ các giá trị cho một thủ tục được lưu trữ, như tôi làm trong ví dụ sau (sử dụng lược đồ bảng ở trên).

Đầu tiên, tạo một stored procedure mà hy vọng một bảng tạm thời đặc biệt để tồn tại trong thời gian chạy, như sau:

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

Một khi bạn đã làm điều đó, tạo ra một kích hoạt sẽ tạo ra và cư trú trong bảng temp mong đợi của quy trình được lưu trữ và sau đó thực hiện quy trình được lưu trữ:

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 

Đó là tất cả về nó. Thật đơn giản, thật dễ dàng, nó hoạt động cho các bộ thay đổi có kích thước bất kỳ. Và, nó an toàn, không có điều kiện chủng tộc hoặc va chạm với những người dùng khác trong hệ thống.

Các vấn đề liên quan