SQL Server 触发器在插入和删除表为空的情况下触发

5
我已经在一个表上定义了一个触发器,该触发器会在以下情况下被触发:插入、删除和更新。有时候触发器会在INSERTEDDELETED表都为空的情况下触发。这是怎么可能的呢?对于记录来说,以下是触发器的代码。
CREATE TRIGGER [dbo].[AuditUsersTrigger] ON [dbo].[Users]
AFTER INSERT, DELETE, UPDATE
AS 
BEGIN
    SET NOCOUNT ON


    DECLARE @type nchar(1), @hasChanges bit
    SET @hasChanges = 1
    IF EXISTS (SELECT * FROM INSERTED)
        IF EXISTS (SELECT * FROM DELETED)
        BEGIN
            SELECT @type = 'U'

            IF EXISTS (
                SELECT *
                FROM INSERTED i
                INNER JOIN DELETED d ON
                    i.Name = d.Name AND
                    i.Pwd = d.Pwd AND
                    ...
            ) SELECT @hasChanges = 0
        END
        ELSE
            SELECT @type = 'I'
    ELSE
        SELECT @type = 'D'


    IF @type = 'D' OR (@type = 'U' AND @hasChanges = 1)
    BEGIN
        INSERT AuditUsers (
            New, Id, Name, ...
        )
        SELECT
            0, Id, Name, ...
        FROM DELETED

        IF @type = 'D'
        BEGIN
            INSERT AuditUsers (New)
            SELECT 1
        END
    END

    IF @type = 'I' OR (@type = 'U' AND @hasChanges = 1)
    BEGIN
        IF @type = 'I'
        BEGIN
            INSERT AuditUsers (New)
            SELECT 0
        END

        INSERT AuditUsers (
            New, Id, Name, ...
        )
        SELECT
            0, Id, Name, ...
        FROM INSERTED
    END


    IF Trigger_Nestlevel() < 2
    BEGIN
        DECLARE @clientId TABLE (id INT)
        DECLARE @clientCode NVARCHAR(50), @shopId INT;

        IF @type = 'I' OR @type = 'U'
        BEGIN
            SELECT @clientCode = ClientCode, @shopId = ShopId FROM INSERTED;
            INSERT INTO @clientId SELECT id FROM Clients WHERE code = @clientCode;

            IF NOT EXISTS (SELECT 1 FROM @clientId)
            BEGIN
                INSERT Clients (name, code, active, shopId) OUTPUT INSERTED.id INTO @clientId
                VALUES (@clientCode, @clientCode, 1, @shopId);
            END


            UPDATE Users SET ClientId = (SELECT TOP 1 id FROM @clientId) WHERE ClientCode = @clientCode;
        END
    END
END

你能展示一下你的触发器的确切定义吗?如果它影响当前表格,那么你就会出现反馈循环。 - apomene
UPDATE ABC SET Column = 1 WHERE 1 = 0 - 未影响任何行,触发器仍然触发。 - Damien_The_Unbeliever
1个回答

11

这是文档记录的行为

DML触发器在用户尝试通过数据操作语言(DML)事件修改数据时执行。DML事件包括对表或视图的INSERT、UPDATE或DELETE语句。这些触发器会在任何有效事件触发时触发,无论是否影响任何表行。

如果你有一个循环递归,其中表A有一个影响表B的触发器,而表B又有一个影响表A的触发器,那么可以使用TRIGGER_NESTLEVEL进行管理,或者在实际操作之前检查inserteddeleted是否包含任何行。


1
我之前排除了那种情况,因为我已经测试过了。结果发现我测试的方式不对。我正在测试嵌套层级。至少现在我知道它是由一个删除语句触发的,而这个语句并没有删除任何东西。谢谢! - alfoks
@GarethD 或者通过检查任一表是否包含任何行来实现 - 这是否就像 select @hasRows = count(my_primary_key) from deleted; if (@hasRows > 0) ... 一样简单? - sab669
是的,但不要忘记 inserted 表。 - GarethD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接