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 可能更快。