使用 JOIN 表触发后

After Trigger with JOIN Tables

任务:创建一个 AFTER TRIGGER 以完成 JOIN 的条件。创建某些记录时,触发器将位于 table_1 中。同时,table_2 有一个公共列,其中包含条件需要具有的一些参数。

每次 table_2 中的结果 <> 1 AND 状态 <> 3 和 ALERT 应该被发送

-- QUERY WITH JOIN TABLE_1 ON TABLE_2

-- MOCK TABLE 

-- Table_1 as A  |    Table_2 as B

   A.LotCode | A.LineNumber  | B.Result  |  B.Status 

    00000    |   xxxx        |   1       |   3
    00001    |   xxxx        |   2       |   4

-- The LotCode 00001 should send it through email because satisfy the condition 
CREATE TRIGGER FullfillOrderQCResult
ON Table_1
AFTER INSERT
AS
BEGIN
      -----DECLARE VARIABLES-----

      DECLARE @LOTNUMBER VARCHAR(50)
      DECLARE @ACTIONPEFORMED VARCHAR(MAX)
      DECLARE @ITEM INT
      DECLARE @RESULT TINYINT
      DECLARE @STATUS TINYINT

      SELECT @LOTNUMBER = A.LotCode, @ITEM = A.LineNumber, @RESULT = B.Result, @STATUS = B.Status
      FROM inserted AS A
      JOIN Table_2 AS B
      ON A.LotCode = B.DocumentID2
    
      -----CONDITION WHEN I INSERT A VALUE-----

      IF (@RESULT <> 1 AND @STATUS <> 3)
      BEGIN     
          SET @ACTIONPEFORMED = 
              N'Hello, ' + '<br>' + '<br>'
              + N'  The following LOT NUMBER: ' + @LOTNUMBER + ' has not been approved for this Item: '  

          EXEC MSDB.DBO.SP_SEND_DBMAIL
            @PROFILE_NAME = 'SQLMail',
            @RECIPIENTS = 'TEST@gmail.com',
            @SUBJECT = 'LOT NON-Approved',
            @BODY = @ACTIONPEFORMED,
            @IMPORTANCE = 'HIGH',
            @BODY_FORMAT = 'HTML'
      END
      ELSE 
            PRINT 'ALL GOOD MY FRIEND'
END
TESTING THE TRIGGER

--------INSERT VALUES------------------

INSERT INTO Table_1 (LotCode,LineNumber)
values ('00000','xxxx')

-----EXISTING VALUES-----

INSERT INTO Table_2 (CreationUser,DocumentID1,DocumentID2,DocumentID3,Result,Status)
values ('JL','00000','00000','00000',2,3)

下面向您展示了如何处理 Inserted 可能有多行的情况。对于触发器来说,这确实不是理想的行为,因为您必须处理结果 RBAR(逐行痛苦),这本身就很慢,更不用说您正在发送电子邮件了。

CREATE TRIGGER FullfillOrderQCResult
ON Table_1
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    -----DECLARE VARIABLES-----

    DECLARE @ACTIONPEFORMED varchar(max), @Id int;

    SELECT A.LotCode, A.LineNumber, CONVERT(bit, 0) Done, IDENTITY(int) id -- Use your own id if you have one, just need to uniquely identify each row.
    INTO #FullfillOrderQCResult_temp
    FROM Inserted AS A
    INNER JOIN Table_2 AS B ON A.LotCode = B.DocumentID2
    WHERE B.Result <> 1 and B.[Status] <> 3;

    WHILE EXISTS (SELECT 1 FROM #FullfillOrderQCResult_temp WHERE Done = 0) BEGIN
        SELECT TOP 1 @Id = id, @ACTIONPEFORMED = 
            N'Hello, ' + '<br>' + '<br>'
            + N'The following LOT NUMBER: ' + LotCode + ' has not been approved for this Item: ' + LineNumber
        FROM #FullfillOrderQCResult_temp
        WHERE Done = 0;

        EXEC MSDB.DBO.SP_SEND_DBMAIL
            @PROFILE_NAME = 'SQLMail',
            @RECIPIENTS = 'TEST@gmail.com',
            @SUBJECT = 'LOT NON-Approved',
            @BODY = @ACTIONPEFORMED,
            @IMPORTANCE = 'HIGH',
            @BODY_FORMAT = 'HTML';

        UPDATE #FullfillOrderQCResult_temp SET Done = 1 WHERE id = @Id;
    END;
END;

我不知道您是否仍需要 'ALL GOOD MY FRIEND' 的概念,因为您可能 none 的某些或所有行都有问题。无论如何,我假设 print 仅用于调试。


也就是说,将事件推入队列并让服务进程处理事件会更好,因为触发器确实应该尽可能快。并且可以以基于集合的方式处理向队列添加事件,例如

CREATE TRIGGER FullfillOrderQCResult
ON Table_1
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO MyEventQueue (A.LotCode, A.LineNumber) -- Any other information required to identify the records etc
        SELECT A.LotCode, A.LineNumber
        FROM Inserted AS A
        INNER JOIN Table_2 AS B ON A.LotCode = B.DocumentID2
        WHERE B.Result <> 1 and B.[Status] <> 3;
END;