关于我为什么使用触发器获得多行的一些指导或指导。基本上,我有一个控制资产类型(例如笔记本电脑,电话等)的Web应用程序,我要使用此触发器执行的操作是当资产类型名称(at_typedesc)更改为我登录到审核表时(在本例中为sql_log) )旧名称是什么,新名称是什么。
这是可行的,但是由于某种原因,我在INSERT TO SQL_LOG语句中写了多行。它的确写了旧名称和新名称,但随后我又得到了3行,其中有旧名称显示了新名称...
当前位于2008 SQL Server上。
-- create the trigger
go
create trigger trg_InsteadOfUpdate on [dbo].[lkp_asset_types]
instead of update
as
begin
DECLARE @triggerAction varchar(1)
-- determine the TRIGGER action
-- this allows us to tell if its an INSERT or an UPDATE
SELECT @triggerAction = CASE
WHEN EXISTS(SELECT 1 FROM INSERTED)
AND EXISTS(SELECT 1 FROM deleted) THEN 'U'
WHEN EXISTS(SELECT 1 FROM inserted) THEN 'I'
ELSE 'D' END;
-- get the orginally asset name from the DELETED table
-- this contains the rows as they were BEFORE the UPDATE Statement
DECLARE @orgAssetTypeName varchar(255)
SET @orgAssetTypeName = (SELECT top 1 at_typedesc from lkp_asset_types WHERE at_id = (select at_id from deleted))
-- UPDATE to the new asset name based on the NEW value in the INSERTED Table
update lkp_asset_types
set at_typedesc = (select at_typedesc from inserted)
where at_id = (select at_id from inserted)
-- get the new asset name from the INSERTED table
-- this contains the rows as they were AFTER the UPDATE Statement
DECLARE @newAssetTypeName varchar(255)
SET @newAssetTypeName = (SELECT top 1 at_typedesc from lkp_asset_types WHERE at_id = (select at_id from inserted))
insert into sql_log
(sql_log)
values ('SQL PRE Changed from : ' + @orgAssetTypeName + ' to: ' + @newAssetTypeName + '. Action = ' + @triggerAction)
end
go
SQL Server触发器中的类似逻辑被破坏:
where at_id = (select at_id from inserted)
我真的希望SQL Server解析器在遇到此类构造时发出警告。
无法保证inserted
只有一个值(也没有deleted
)。
这就是SQL Server将触发器定义为set操作的方式。如果同时插入多行,则inserted
和deleted
“表”具有多行。
这部分很简单。您需要重写触发器以考虑到这一点。
在检查我的Web代码时,更新按钮正在执行其他更新,这导致触发器多次触发,从而导致重复的行。
create table dbo.lkp_asset_types_test
(
at_id int identity,
at_typedesc varchar(100)
)
go
create trigger trg_InsteadOfUpdate_test on [dbo].[lkp_asset_types_test]
instead of update
as
begin
select 'trigger fired!!!!'
if not exists(select * from inserted)
and not exists(select * from deleted)
begin
return;
end
--update (maybe only the diffs?)
update t
set at_typedesc = i.at_typedesc
from dbo.lkp_asset_types_test as t
join inserted as i on t.at_id = i.at_id;
--where t.at_typedesc <> i.at_typedesc & nulls??
--insert into sql_log(sql_log)
select
'SQL PRE Changed from : ' + isnull(d.at_typedesc, '*null*') + ' to: ' + isnull(i.at_typedesc, '*null*') + '. Action = U'
from inserted as i
join deleted as d on i.at_id = d.at_id
--where i.at_typedesc <> d.at_typedesc & nulls ??
end
go
insert into dbo.lkp_asset_types_test(at_typedesc) values ('A'), ('B'), ('C'), ('D'), (NULL);
go
update dbo.lkp_asset_types_test
set at_typedesc = case when at_id%2=0 then isnull(at_typedesc, 'X') else isnull(at_typedesc, '') + 'xyz' end
go
select *
from dbo.lkp_asset_types_test;
go
update dbo.lkp_asset_types_test
set at_typedesc = case when at_id%2=0 then at_typedesc else at_typedesc + 'xyz' end
where 1=2
go
--
drop table lkp_asset_types_test;