SQL Server 存储过程:等待删除触发器完成,然后再继续该过程

Posted

技术标签:

【中文标题】SQL Server 存储过程:等待删除触发器完成,然后再继续该过程【英文标题】:SQL Server stored procedure: wait for a delete's trigger to finish before continuing in the procedure 【发布时间】:2018-11-11 17:35:07 【问题描述】:

我的存储过程执行了一个删除语句,该语句触发了一个触发器,该触发器无法记录谁删除了该行,但为changed_by 记录了一个空白。

然后存储过程用它给定的用户名更新changed_by

一半的时间,下面存储过程的part 2找到了触发器的结果,另一半的时间,它没有找到触发器的结果,所以没有什么要更新的。

在继续存储过程之前,我如何“让步”控制并确保更新的触发器完成?

(在 cmets 中,您会看到我迄今为止尝试过的一些事情没有奏效)

DROP PROCEDURE IF EXISTS dbo.deleteAndUpdateChangedByInAuditTrail
GO

CREATE PROCEDURE dbo.deleteAndUpdateChangedByInAuditTrail 
     (@tableName VARCHAR(100), 
      @pkIDColName VARCHAR(100), 
      @pkIDValue NUMERIC,
      @delUser VARCHAR(100) )
AS
     BEGIN TRANSACTION;
        -- PART 1: DO THE DELETE:
        DECLARE @JUST_BEFORE_DELETION_TIMESTAMP AS DATETIME2;

        SET @JUST_BEFORE_DELETION_TIMESTAMP = CONVERT(varchar, SYSDATETIME(), 121);

        DECLARE @DELETION_TEMPLATE AS VARCHAR(MAX);
        SET @DELETION_TEMPLATE = 'delete from THE_TABLE_NAME WHERE PK_ID_COL_NAME = PK_ID_VALUE';
        SET @DELETION_TEMPLATE = REPLACE(@DELETION_TEMPLATE, 'THE_TABLE_NAME', @tableName);
        SET @DELETION_TEMPLATE = REPLACE(@DELETION_TEMPLATE, 'PK_ID_COL_NAME', @pkIDColName);
        SET @DELETION_TEMPLATE = REPLACE(@DELETION_TEMPLATE, 'PK_ID_VALUE', @pkIDValue);

        --PRINT @DELETION_TEMPLATE
        EXEC (@DELETION_TEMPLATE);

    COMMIT TRANSACTION;

    BEGIN TRANSACTION;
        -- PART 2: UPDATE THE AUDIT_TRAIL:

        DECLARE @TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME AS NUMERIC;
        SET @TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME = 0;

        --DECLARE @TOTAL_TRIES_SO_FAR AS NUMERIC;
        --SET @TOTAL_TRIES_SO_FAR = 0;

        --WHILE @TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME < 1 AND @TOTAL_TRIES_SO_FAR < 5
        --BEGIN  

            --SET @TOTAL_TRIES_SO_FAR = @TOTAL_TRIES_SO_FAR + 1;

            --WAITFOR DELAY '00:00:01.000' -- SEEN IT FAIL FOR 4 SECONDS :(

            DECLARE @UPDATE_AUDIT_TRAIL_TEMPLATE AS VARCHAR(MAX);

            SET @UPDATE_AUDIT_TRAIL_TEMPLATE = 'update AUDIT_TRAIL set changed_by = ''CHANGED_BY'' WHERE upper(table_name) = upper(''THE_TABLE_NAME'') and table_pk_value = PK_ID_VALUE and CONVERT(varchar, changed_at, 121) >= ''CHANGED_AT'' ';

            SET @UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(@UPDATE_AUDIT_TRAIL_TEMPLATE, 'CHANGED_BY', @delUser); 
            SET @UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(@UPDATE_AUDIT_TRAIL_TEMPLATE, 'THE_TABLE_NAME', @tableName); 
            SET @UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(@UPDATE_AUDIT_TRAIL_TEMPLATE, 'PK_ID_VALUE', @pkIDValue); 
            SET @UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(@UPDATE_AUDIT_TRAIL_TEMPLATE, 'CHANGED_AT', @JUST_BEFORE_DELETION_TIMESTAMP); 

            --PRINT @UPDATE_AUDIT_TRAIL_TEMPLATE

            EXEC (@UPDATE_AUDIT_TRAIL_TEMPLATE);

            SELECT @TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME = @@ROWCOUNT;

        --END

    COMMIT TRANSACTION;

    RETURN @TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME;
GO

【问题讨论】:

您不应该(绝对从不)将日期作为字符串进行比较。使用适当的数据类型,这就是它们的用途,我毫不怀疑这是您当前问题的原因。您还应该始终定义varchar的长度。 谢谢,我改成 SYSDATETIME(),还是报错,然后改成 CURRENT_TIMESTAMP,好像一切正​​常。 【参考方案1】:

触发器不会异步执行。在触发器完成之前,DELETE 之后的下一步不会发生。

如果你看到的东西让你产生了不同的想法,那是有其他原因的。不是因为触发器“没有完成”。

【讨论】:

以上是关于SQL Server 存储过程:等待删除触发器完成,然后再继续该过程的主要内容,如果未能解决你的问题,请参考以下文章

批量删除Sql Server对象(表,存储过程,触发器)

SQL Server 触发器事务以及存储过程详解

20180927 SQL server ProcedureT-SQL创建前删除已存在存储过程

SQL Server 触发器

SQL Server 触发器

SQL Server 触发器