在 SQL 服务器中使用触发器批量更新同一行列

Bulk update of the same row column using trigger in SQL Server

我有这个 table 结构:

CREATE TABLE JoiningDate 
(
    Id INT,
    DateofJoining DATETIME,
    STATUS VARCHAR(10),
    DaysCount INT
)

此 table 填充了 1000 条记录,DaysCount 为 NULL 值。

我已经为这个 table 创建了一个触发器来更新 DaysCount。每当更新 DateOfJoiningStatus 列时,DaysCount 应该在触发器中计算并自动更新。

这是触发器的轮廓:

CREATE TRIGGER [dbo].[trigger_JoiningDate] 
ON [dbo].[JoiningDate]
AFTER INSERT, UPDATE
AS
BEGIN
    DECLARE @Id INT
    DECLARE @DateJoining DATETIME
    DECLARE @Result INT

    SELECT @Id = Id,
           @DateJoining = DateofJoining, 
    FROM INSERTED   

    SET @Result = [Formula To Calculate Days]

    UPDATE JoiningDate 
    SET DaysCount = @Result  
    WHERE Id = @Id
END

我可以看到单个记录的计数得到更新。但对于批量更新,它只更新第一条记录。

在 Whosebug 的帮助下,我尝试使用 TRIGGER_NESTLEVEL() 等选项来代替触发器,但所有其他行仍然没有得到更新。

感谢更快的帮助。

只有一条记录得到更新,因为即使是批量记录,您也只更新了一条记录。

此外,您还应该说出您的确切公式是什么样的。

您应该将代码更改为:

DECLARE @Id INT
  DECLARE @DateJoining DATETIME
  DECLARE @Result INT

    Declare @Flg int=0
    --if exists(select top 1 id from inserted)
    --set @Flg=1
    --if exists(select top 1 id from deleted)
    --set @Flg=@Flg+2
    if (COLUMNS_UPDATED(DateJoining) or COLUMNS_UPDATED([status]))
    begin

  SET @Result = [Formula To Calculate Days]
  --what is the actual formula ?
  UPDATE jd SET DaysCount = @Result  
        FROM INSERTED i
        inner join JoiningDate jd on i.id=jd.id  
end

我建议将其拆分为 两个 个单独的触发器 - 一个用于 INSERT,一个用于 UPDATE。使使用代码变得更加简单。

此外:您的触发器将在每个语句中被调用 一次 - 每行 而不是 一次 - 所以你不能只 select来自 Inserted 伪 table 的值(因为伪 table 将包含 all 25 个新插入的行 - 而不仅仅是一个):

SELECT 
    @Id = Id,
    @DateJoining = DateofJoining, 
FROM INSERTED   

您会查看插入的 25 行中的哪一行??它是任意的和不确定的 - 另外你将只看 一个 行并忽略所有其他 24 行.....

所以 INSERT 触发器应该如下所示:

CREATE TRIGGER [dbo].[trigger_JoiningDate_Insert] 
ON [dbo].[JoiningDate]
AFTER INSERT
AS
BEGIN
    UPDATE jd
    SET DaysCount = [Formula To Calculate Days]
    FROM JoiningDate jd
    INNER JOIN Inserted i ON i.Id = jd.Id
END

由于您没有以前的值,因此无需检查这两列之一是否已更新。

您的 UPDATE 触发器应如下所示:

CREATE TRIGGER [dbo].[trigger_JoiningDate_Update] 
ON [dbo].[JoiningDate]
AFTER UPDATE
AS
BEGIN
    UPDATE jd
    SET DaysCount = DATEDIFF(DAY, jd.DateofJoining, SYSDATETIME())
    FROM JoiningDate jd
    INNER JOIN Inserted i ON i.Id = jd.Id
    INNER JOIN Deleted d ON d.Id = i.Id
    -- check whether "DateOfJoining" or "Status" have been updated
    WHERE
        i.DateOfJoining <> d.DateOfJoining 
        OR i.Status <> d.Status 
END