如何使触发器与两个源表一起工作?

Posted

技术标签:

【中文标题】如何使触发器与两个源表一起工作?【英文标题】:How can I made a trigger work with two source tables? 【发布时间】:2021-08-15 14:16:01 【问题描述】:

我无法让此触发器正常工作。我很少使用触发器,所以我对它们的理解可能有点偏离,因为我编写此代码的方式似乎应该有效(至少对我而言)但它没有。如果对 tblCollat​​eralAssignment 进行了更新,则触发器正常工作并将所有信息保存在 tblCollat​​eralAssignmentHistory 表中(包括来自 CustodianData 表的任何信息)。

但是,如果进行的更新仅涉及 CustodianData 表(例如,仅更新 CustodianFrom 字段)并且没有涉及 tblCollat​​eralAssignemnt 中的任何字段,则触发器不起作用并且更新不会保存到 tblCollat​​eralAssignmentHistory。

希望我只是忽略了一些小东西,但我一直盯着它看,不知所措。

ALTER TRIGGER [dbo].[Trigger_tblCollateralAssignmentToHistory]
   ON [dbo].[tblCollateralAssignment] AFTER UPDATE
AS 

SET NOCOUNT ON;

IF EXISTS ( SELECT ChainID FROM inserted ) AND EXISTS ( SELECT ChainID FROM deleted )
    BEGIN
    
        --This updates history with the changed records.
        INSERT INTO dbo.tblCollateralAssignmentHistory
        SELECT i.ChainID
              ,d.LoanNo
              ,d.FileDate as BeginFileDate
              ,i.FileDate as EndFileDate
              ,d.ModifiedBy
              ,d.RecordSource
              ,d.AssignmentNo
              ,d.AssignmentFrom
              ,d.AssignmentTo
              ,d.RecordedDate
              ,d.StatusPerTitle
              ,d.RecordedImage
              ,d.AtCustodian
              ,d.AOMComments
              ,d.IsVisible
              ,d.DocXNotarized
              ,d.AOMBook
              ,d.AOMDocumentNo
              ,d.AOMPage
              ,d.CorrectiveAssignment
              ,d.DocumentID
              ,d.DocumentDetails
              ,cd.CustodianUID
              ,cd.CustodianDocCode AS DocCode
              ,d.MASIdentified
              ,cd.CustodianExceptionDescription AS ExceptionDescription
              ,cd.CustodianFrom
              ,cd.CustodianTo
              ,cd.CustodianNotation
              ,cd.CustodianComments
        FROM deleted as d
        JOIN inserted as i on i.ChainID = d.ChainID
        LEFT JOIN ExternalReports.CustodianData AS cd ON cd.ChainId = i.ChainID
    END

--Clear out CorrectiveAssignment if the related ChainID IsVisible is set to false.  This is a trigger enacted cascade delete for soft deleted chains.  Edited records are also copied to history.
DECLARE @FileDate datetime = GETDATE();
UPDATE 
    dbo.tblCollateralAssignment
SET 
    CorrectiveAssignment = NULL,
    FileDate = @FileDate
OUTPUT  
    inserted.ChainID,
    deleted.LoanNo,
    deleted.FileDate AS BeginFileDate,
    @FileDate AS EndFileDate,
    deleted.ModifiedBy,
    deleted.RecordSource,
    deleted.AssignmentNo,
    deleted.AssignmentFrom,
    deleted.AssignmentTo,
    deleted.RecordedDate,
    deleted.StatusPerTitle,
    deleted.RecordedImage,
    deleted.AtCustodian,
    deleted.AOMComments,
    deleted.IsVisible,
    deleted.DocXNotarized,
    deleted.AOMBook,
    deleted.AOMDocumentNo,
    deleted.AOMPage,
    deleted.CorrectiveAssignment,
    deleted.DocumentID,
    deleted.DocumentDetails,
    cd.CustodianUID,
    cd.CustodianDocCode AS DocCode,
    deleted.MASIdentified,
    cd.CustodianExceptionDescription AS ExceptionDescription,
    cd.CustodianFrom,
    cd.CustodianTo,
    cd.CustodianNotation,
    cd.CustodianComments    
INTO 
    dbo.tblCollateralAssignmentHistory
FROM 
    dbo.tblCollateralAssignment AS CorrectiveAssignment
LEFT JOIN
    ExternalReports.CustodianData AS cd ON cd.ChainId = CorrectiveAssignment.ChainID
WHERE EXISTS 
    (select * from dbo.tblCollateralAssignment as DeletedAssignment where DeletedAssignment.IsVisible = 0 and DeletedAssignment.ChainID = CorrectiveAssignment.CorrectiveAssignment)
AND 
    CorrectiveAssignment is not null
AND EXISTS
    (select * from inserted AS i where i.LoanNo = CorrectiveAssignment.LoanNo);

【问题讨论】:

触发器是高度特定于供应商的 - 所以请添加一个标签来指定您使用的是mysqlpostgresqlsql-serveroracle 还是db2 - 或完全不同的东西。 不确定您期望table A 上的触发器如何同时处理Table B 上的更新。您将需要在每个表上都有一个触发器。 我猜 OP 正在使用 MS SQL Server。 您好,很抱歉没有标记供应商。我正在使用 sql 服务器。 @Stu那么不可能使用单个触发器从两个源表中填充目标历史表吗?只能使用两个触发器来完成吗?基本上,我们过去只有 tblCollat​​eralAssignment(保存最新信息),然后是 tblCollat​​eralAssignmentHistory,它保存了 tblCollat​​eralAssignment 中的所有条目。该数据通过触发器到达那里。但我们最近将 5 个字段从 tblCollat​​eralAssignment 移出并移至 CustodianData。所以我试图让触发器工作。 难道不能使用单个触发器从两个源表中填充目标历史表吗? 是的; 只能使用两个触发器来完成? 是的 【参考方案1】:

希望这会奏效

CREATE OR REPLACE TRIGGER checkDuration
  BEFORE INSERT OR UPDATE on offering
  FOR EACH ROW
DECLARE
  isFound NUMBER;
BEGIN
  SELECT 1 INTO isFound FROM DUAL WHERE EXISTS (
    SELECT * FROM Course c
    WHERE c.courseId = :new.courseId AND c.duration = 5);
  IF EXTRACT(MONTH FROM :new.startDate) = 12 
    THEN RAISE_APPLICATION_ERROR(-20001, 'Courses of five days duration cannot be run in December');
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    NULL;
END;

【讨论】:

以上是关于如何使触发器与两个源表一起工作?的主要内容,如果未能解决你的问题,请参考以下文章

pt-osc在线工具的使用

触发器实现源表操作(增,删,改)自动补录操作日志

percona pt toolkit 总结

[生产库实战] 如何使用触发器对生产库上亿级大表进行实时同步

如何设置 lambda 函数以一起使用两个触发器

MySQL--pt-osc工具学习