SQL 服务器触发器将数据插入或更新到单独的 table
SQL Server trigger to insert or update data into a separate table
我有一个 SQL 我正在编写的 Server 2012 插入触发器,它需要有条件地插入或更新单独的 table.
中的现有行
插入的每一行都需要单独评估,并且有可能在一次提交中插入多行。
触发器所在的 table 仅被插入。有一个业务要求,对于给定的 AlarmId
,初始插入将用于设置警报信息,并且该 AlarmId
的后续插入将被忽略,除非该插入包含 EndTime
,此时复制的数据将更新为包含 EndTime
.
因此,table 的相关部分将是:
ID | AlarmId | StartTime | EndTime
(极其简化的)触发器如下:
DECLARE @AlarmId AS INT
SET @AlarmId = SELECT AlarmId FROM inserted
IF (SELECT COUNT(AlarmId) FROM destinationTable WHERE AlarmId = @AlarmId) <= 0
BEGIN
-- Handle insert here
END
ELSE
BEGIN
-- Handle update here
END
我们这里没有 T-SQL 开发人员,因此我们将不胜感激任何有关如何解决此问题的帮助。我相信游标是到达此处的正确方法,但我不确定,并且愿意接受任何想法。
我认为这应该用作插入触发器:
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)
没有对此进行测试,但希望它有效。如果您还对 table 进行更新,则必须单独处理。
人们在使用触发器时犯的最大错误是假设插入的 and/or 删除的集合仅包含一行。对于插入,几乎可以肯定对于更新和删除,很可能会有多行。
你肯定也想避免游标。特别是在触发器中。性能会很糟糕。
这里有一个简单的基于集合的解决方案,大致如下:
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 仅更新已存在的行。
希望对您有所帮助。
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
将是您的跟踪 table。必须添加许多空白行,以便您可以剪切和粘贴示例。喜欢使用 exist
而不是 count(*)
但 count(*)
也可以。 Exist
可能更快。
我有一个 SQL 我正在编写的 Server 2012 插入触发器,它需要有条件地插入或更新单独的 table.
中的现有行插入的每一行都需要单独评估,并且有可能在一次提交中插入多行。
触发器所在的 table 仅被插入。有一个业务要求,对于给定的 AlarmId
,初始插入将用于设置警报信息,并且该 AlarmId
的后续插入将被忽略,除非该插入包含 EndTime
,此时复制的数据将更新为包含 EndTime
.
因此,table 的相关部分将是:
ID | AlarmId | StartTime | EndTime
(极其简化的)触发器如下:
DECLARE @AlarmId AS INT
SET @AlarmId = SELECT AlarmId FROM inserted
IF (SELECT COUNT(AlarmId) FROM destinationTable WHERE AlarmId = @AlarmId) <= 0
BEGIN
-- Handle insert here
END
ELSE
BEGIN
-- Handle update here
END
我们这里没有 T-SQL 开发人员,因此我们将不胜感激任何有关如何解决此问题的帮助。我相信游标是到达此处的正确方法,但我不确定,并且愿意接受任何想法。
我认为这应该用作插入触发器:
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)
没有对此进行测试,但希望它有效。如果您还对 table 进行更新,则必须单独处理。
人们在使用触发器时犯的最大错误是假设插入的 and/or 删除的集合仅包含一行。对于插入,几乎可以肯定对于更新和删除,很可能会有多行。
你肯定也想避免游标。特别是在触发器中。性能会很糟糕。
这里有一个简单的基于集合的解决方案,大致如下:
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 仅更新已存在的行。
希望对您有所帮助。
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
将是您的跟踪 table。必须添加许多空白行,以便您可以剪切和粘贴示例。喜欢使用 exist
而不是 count(*)
但 count(*)
也可以。 Exist
可能更快。