我正在编写一个SQL Server 2012插入触发器,需要在一个单独的表中有条件地插入或更新现有行。
每个插入的行都需要单独计算,并且可能会在一次提交中插入多行。
触发器所在的表只能插入。有一个业务要求,对于给定的AlarmId
,初始插入将用于设置警报的信息,并且将忽略该AlarmId
的后续插入,除非该插入包含{{ 1}},此时复制的数据将更新为包含EndTime
。
因此,该表的相关部分将是:
EndTime
(极简化)触发器如下:
ID | AlarmId | StartTime | EndTime
我们这里没有T-SQL开发人员,因此非常感谢任何有关如何解决此问题的帮助。我相信光标是走到这里的正确方式,但我不确定,并且对任何想法持开放态度。
答案 0 :(得分:2)
人们使用触发器犯的最大错误是假设插入和/或删除的集合只包含一行。插入很可能,并且几乎可以确定更新和删除,可能会有多行。
你当然也想避免游标。特别是在触发器中。表现太糟糕了。
这里有一个简单的基于集合的解决方案,这将是:
UPDATE dt
SET column=value, etc, etc
FROM destinationTable dt
INNER JOIN inserted i ON dt.AlarmId = i.AlarmId
INSERT INTO destinationTable (your list of columns here)
SELECT (list of columns)
FROM inserted i
WHERE NOT EXISTS (SELECT 1 FROM destinationTable WHERE AlarmId = i.AlarmId)
INSERT仅插入数据尚不存在的位置... UPDATE仅更新已存在的行。
我希望这会有所帮助。
答案 1 :(得分:1)
我认为这应该作为插入触发器工作:
update d
set d.EndTime = i.EndTime
from
destinationTable d
join inserted i on i.AlarmId = d.AlarmId
where
i.EndTime is not NULL
insert into destinationTable (AlarmId,StartTime,EndTime)
select AlarmId, StartTime, EndTime
from inserted i
where not exists (select 1 from destinationTable d
where d.AlarmId = i.alarmId)
没有测试过这个,但希望它有效。如果您还对表格进行了更新,那么您必须单独处理。
答案 2 :(得分:0)
create table dbo.t5 (
id int identity,
AlarmId int,
StartTime datetime,
EndTime datetime
)
;
go
create table
dbo.watched (alarmid int,
endtime datetime)
;
go
create trigger dbo.t1 on dbo.watched after insert as
begin
set nocount on
Declare @AlarmId AS INT
Declare @endtime datetime
Select @AlarmId =AlarmId FROM inserted
Select @endtime = endtime from inserted
IF exists (SELECT AlarmId FROM dbo.t5 WHERE AlarmId = @AlarmId)
/* we already have an entry for this alarmid */
BEGIN
if @endtime is not null
/* is this the terminal entry? */
begin
select 'hello'
update dbo.t5 set EndTime = @endtime where AlarmId = @Alarmid
end
END
ELSE
/* first time seeing this alarmid - create it */
BEGIN
insert into dbo.t5 (AlarmID,StartTime)
values (@AlarmId, GETDATE())
END
end
; go
insert into dbo.watched (alarmid) values (1234)
insert into dbo.watched (alarmid) values (1234)
select * from dbo.t5
insert into dbo.watched (alarmid,endtime)
values (123, GETDATE())
select * from dbo.t5 where AlarmId=123
dbo.t5
将成为您的跟踪表。必须添加许多空白行,以便您可以剪切和粘贴示例。喜欢使用exist
代替count(*)
,但count(*)
也可以。 Exist
可能更快。