如何在SQL触发器中获取更新记录的值 - 如下所示:
CREATE TRIGGER TR_UpdateNew
ON Users
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
EXEC UpdateProfile (SELECT UserId FROM updated AS U);
END
GO
显然这不起作用,但你可以看到我想要的东西。
答案 0 :(得分:11)
提供您某些只会更新一个值,您可以这样做...
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 :(得分:2)
根据我的知识,您需要创建一个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
我的语法可能有些偏差,但这会给你带来理想的效果。同样,考虑修改逻辑以处理多个更新,因为使用游标是资源密集型的。
答案 2 :(得分: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
这就是它的全部内容。它很简单,很容易,适用于任何大小的变更集。并且,它是安全的,没有竞争条件或与系统中的其他用户发生冲突。