批量更新情况下,UPDATE(column)函数是如何工作的?

huangapple go评论74阅读模式
英文:

How UPDATE(column) function works in case of batch updates?

问题

SQL Server触发器在批处理上执行,而不是在更新事务中的每一行上执行。

如果在单个事务中更新了表的'N'行,UPDATE触发器将在'N'行一起执行。 (UPDATE(): MS Docs链接)

在这种情况下,触发器函数UPDATE()如何工作?假设有以下表:

CREATE TABLE [dbo].[Sample](
    SampleId INT IDENTITY(1,1) NOT NULL,
    Column1 VARCHAR(100) NULL,
    CONSTRAINT [PK_Sample] PRIMARY KEY CLUSTERED (SampleId ASC)
);

考虑对该表的更新:

UPDATE Sample SET Column1 = 'Example' WHERE SampleId <= 5;

如果在上述表的更新触发器中存在以下条件:

IF UPDATE(Column1)
  • 如果'N'次更新中的每次更新都对Column1进行更新,那么上述条件是否会评估为True,还是它只要在'N'次更新中的任何一次更新中对Column1进行了更新就会评估为True?
  • 或者是否有一种方法可以对每次更新逐个使用它?

编辑: <br>
如果在单个事务中对同一表进行了2次不同的更新,更新触发器会为每个更新语句触发一次,还是只触发一次来处理该事务中的所有更新?

英文:

SQL Server triggers execute on batches instead of each row in the update transaction.

If 'N' rows of a table were updated in a single transaction, the UPDATE Trigger will execute on the 'N' rows together. (UPDATE(): Link to MS Docs)

How does the trigger function UPDATE() work in such scenario, assuming the following table:

CREATE TABLE [dbo].[Sample](
    SampleId INT IDENTITY(1,1) NOT NULL,
    Column1 VARCHAR(100) NULL,
    CONSTRAINT [PK_Sample] PRIMARY KEY CLUSTERED (SampleId ASC)
);

Considering this update on the table:

UPDATE Sample SET Column1 = &#39;Example&#39; WHERE SampleId &lt;= 5;

And, if inside the update trigger for above table there is this condition:

IF UPDATE(Column1)
  • Will the above condition evaluate to True if Column1 is updated in each of the 'N' updates, or will it evaluate to True if any one of the 'N' updates have an update on Column1?
  • Or is there a way to use it on each update one by one?

Edit: <br>
If there are 2 different updates on the same table in a single transaction, will the Update trigger fire once for each Update statement, or once for all updates in that transaction?

答案1

得分: 4

如果在UPDATESET子句中包含了该列,UPDATE()函数返回true;就是这么简单。UPDATE()函数考虑的是语句而不是行或数据。

以这个简单的语句为例:

UPDATE SomeTable
SET SomeColumn = 1
WHERE SomeColumn = 1

这将导致UPDATE(SomeColumn)trueSomeColumn包含在SET子句中。UPDATE(AnotherColumn)false,因为它没有包含在其中。

如果有多行受影响,或者一个都没有,都无所谓。

作为一个完整的工作示例:

CREATE TABLE dbo.SomeTable (ID int IDENTITY(1,1),
                            SomeInt int,
                            SomeString varchar(10));
GO

INSERT INTO dbo.SomeTable (SomeInt, SomeString)
VALUES(1, 'abc'),
      (2, 'def'),
      (2, 'ghi');
GO

CREATE TRIGGER trg_SomeTrigger ON dbo.SomeTable
AFTER UPDATE AS
BEGIN

    IF UPDATE(SomeString)
        PRINT N'SomeString was updated';
END;
GO
--打印语句,SomeString已更新。
--影响了1行,但值没有改变。
UPDATE dbo.SomeTable
SET SomeString = 'abc'
WHERE SomeInt = 1;
GO
--打印语句,SomeString已更新。
--影响了2行,值已改变。
UPDATE dbo.SomeTable
SET SomeString = '123'
WHERE SomeInt = 2;
GO
--打印语句,SomeString已更新。
--没有影响任何行,值没有改变。
UPDATE dbo.SomeTable
SET SomeString = 'abc'
WHERE SomeInt = 3;
GO
--不会打印语句,因为SomeString未更新。
--影响了1行,但不是SomeString。
UPDATE dbo.SomeTable
SET SomeInt = 3
WHERE SomeInt = 1;
GO

DROP TABLE dbo.SomeTable;

如果要检查行和列的值是否已更改,您需要检查inserteddeleted伪表中的值。如果您使用SQL Server 2022,使用IS DISTINCT FROM要容易得多。在较旧的版本中,如果列是可为NULL,您还需要确保检查这一点。例如:

CREATE TRIGGER trg_AnotherTrigger ON dbo.SomeTable
AFTER UPDATE AS
BEGIN

    IF EXISTS (SELECT 1
               FROM inserted i
                    JOIN deleted d ON i.ID = d.ID
               WHERE i.SomeString IS DISTINCT FROM d.SomeString)
        PRINT N'SomeString was updated and a value was changed';
END;

上面的触发器只会对第二个UPDATE语句进行PRINT,其中SomeString的值已更改。
db<>fiddle

英文:

If the column is included in the SETclause of the UPDATE then UPDATE() returns true; it's as simple as that. UPDATE() considers the statement not the row or the data.

Take a simple statement like this:

UPDATE SomeTable
SET SomeColumn = 1
WHERE SomeColumn = 1

This would result in UPDATE(SomeColumn) being true; SomeColumn was included in the SET clause. UPDATE(AnotherColumn) would be false, as it wasn't included.

If there are multiple rows effected, or none, it doesn't matter.

As a full working example:

CREATE TABLE dbo.SomeTable (ID int IDENTITY(1,1),
                            SomeInt int,
                            SomeString varchar(10));
GO

INSERT INTO dbo.SomeTable (SomeInt,SomeString)
VALUES(1,&#39;abc&#39;),
      (2,&#39;def&#39;),
      (2,&#39;ghi&#39;);
GO

CREATE TRIGGER trg_SomeTrigger ON dbo.SomeTable
AFTER UPDATE AS
BEGIN

    IF UPDATE(SomeString)
        PRINT N&#39;SomeString was updated&#39;;
END;
GO
--Prints statement, SomeString was updated.
--1 row is affected, though the value doesn&#39;t change.
UPDATE dbo.SomeTable
SET SomeString = &#39;abc&#39;
WHERE SomeInt = 1;
GO
--Prints statement, SomeString was updated.
--2 rows are affected, the values do change.
UPDATE dbo.SomeTable
SET SomeString = &#39;123&#39;
WHERE SomeInt = 2;
GO
--Prints statement, SomeString was updated.
--0 rows are affected, no values change.
UPDATE dbo.SomeTable
SET SomeString = &#39;abc&#39;
WHERE SomeInt = 3;
GO
--Doesn&#39;t Print statement, as SomeString wasn&#39;t updated.
--1 row is affected, but not SomeString.
UPDATE dbo.SomeTable
SET SomeInt = 3
WHERE SomeInt = 1;
GO

DROP TABLE dbo.SomeTable;

If you want to check if a row and column's value has changed you need to inspect the values in the inserted and deleted pseudo tables. If you are on SQL Server 2022 then this is much easier with IS DISTINCT FROM. On older versions, if the column is NULLable you'll need to ensure you check for that too. For example:

CREATE TRIGGER trg_AnotherTrigger ON dbo.SomeTable
AFTER UPDATE AS
BEGIN

    IF EXISTS (SELECT 1
               FROM inserted i
                    JOIN deleted d ON i.ID = d.ID
               WHERE i.SomeString IS DISTINCT FROM d.SomeString)
        PRINT N&#39;SomeString was updated and a value was changed&#39;;
END;

The above trigger would only PRINT for the second UPDATE statement, where values of SomeString where changed.
db<>fiddle

huangapple
  • 本文由 发表于 2023年4月4日 15:56:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75926835.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定