使用和UPDATE触发器修改正在更新的行

时间:2014-02-10 21:27:00

标签: sql-server-2008

我有一个员工表(em),其中包含楼层ID(fl_id)和房间ID(rm_id)。在某些情况下(当em_loc_cnt = 0时)我想将em记录的fl_id和rm_id设置为null。以下是我目前的代码。

我不确定如何引用fl_id&注释行中的rm_id。我是否会遇到问题,因为正在更新em记录并且我在触发器中更新相同记录会调用此触发器?

建议?

IF EXISTS (SELECT * FROM [sysobjects] WHERE [name] = 'em_upd_self_serv_t' AND [type] = 'TR')
  BEGIN
    DROP TRIGGER [dbo].[em_upd_self_serv_t]
 END
GO

CREATE TRIGGER [dbo].[em_upd_self_serv_t]
  ON [dbo].[em]
  AFTER UPDATE
AS
BEGIN
  DECLARE @em_id VARCHAR(35),
          @em_loc_cnt INT;

  SET @em_id = (SELECT em_id FROM inserted);
  SET @em_loc_cnt = (SELECT COUNT(*) FROM emlocs WHERE em_id = @em_id);

  IF (@em_loc_cnt = 0) 
    BEGIN
      -- I want to set the fl_id and the rm_id to NULL
    END
END;

1 个答案:

答案 0 :(得分:2)

您的根本缺陷是,您似乎希望触发器每行一次 - 这在SQL Server中是 NOT 。相反,触发器会在每个语句时触发,而伪表Inserted可能包含多行

鉴于该表可能包含多行 - 您希望在这里选择哪一行?

SET @em_id = (SELECT em_id FROM inserted);

未定义 - 您可以从Inserted中的任意行获取值。

您需要使用Inserted WILL 包含多行的知识重写整个触发器!您需要使用基于集合的操作 - 不要只期望Inserted中的一行!

您需要将代码更改为以下内容:

IF EXISTS (SELECT * FROM sys.triggers WHERE [name] = 'em_upd_self_serv_t')
    DROP TRIGGER [dbo].[em_upd_self_serv_t]
GO

CREATE TRIGGER [dbo].[em_upd_self_serv_t]
  ON [dbo].[em]
  AFTER UPDATE
AS
   UPDATE dbo.em
   SET fl_id = NULL, rm_id = NULL
   FROM Inserted i
   WHERE em_id = i.em_id
     AND NOT EXISTS (SELECT * FROM dbo.emlocs WHERE em_id = i.em_id)