在 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
。每当更新 DateOfJoining
或 Status
列时,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
我有这个 table 结构:
CREATE TABLE JoiningDate
(
Id INT,
DateofJoining DATETIME,
STATUS VARCHAR(10),
DaysCount INT
)
此 table 填充了 1000 条记录,DaysCount 为 NULL 值。
我已经为这个 table 创建了一个触发器来更新 DaysCount
。每当更新 DateOfJoining
或 Status
列时,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