【问题标题】:PostgreSQL Trigger that updates table where original trigger runs fromPostgreSQL 触发器更新原始触发器运行的表
【发布时间】:2020-05-07 17:01:46
【问题描述】:

在这种情况下,我有两张桌子。一个是我的“热同步”表,它是从我的 Salesforce 组织到 Postgres 表的近实时双向同步数据。随着源系统 (Salesforce) 中的数据发生变化,它会更新 Postgres 上的该表。

在 Postgres 的这张表上,我有一个运行一些逻辑的触发器。它基本上检查触发它的记录是否具有满足某些业务逻辑的发送日期,将该行复制到另一个架构/表中以“归档”它。

这一切都很好。

然而,我需要做的是,一旦将这一行复制到另一个表中,我需要更新记录热同步表的状态。由于它是双向的,这将允许 Salesforce 中的数据反映我在 Postgres 方面所做的更改。

我可以将此更新语句放在原始触发器中还是会导致递归问题?

CREATE FUNCTION salesforce.archivelogicfunc()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$   BEGIN
    IF (DATE(NEW.et4ae5__datesent__c) < NOW() - INTERVAL '180 days' 
    AND DATE(NEW.et4ae5__datesent__c) > NOW() - INTERVAL '540 days')
    THEN
      INSERT INTO archive.individualemailresult__c 
            (dateopened__c, 
             numberoftotalclicks__c, 
             datebounced__c, 
             fromname__c, 
             hardbounce__c, 
             fromaddress__c, 
             softbounce__c, 
             name, 
             lastmodifieddate, 
             opened__c, 
             ownerid, 
             subjectline__c, 
             isdeleted, 
             contact__c, 
             systemmodstamp, 
             lastmodifiedbyid, 
             datesent__c, 
             dateunsubscribed__c, 
             createddate, 
             createdbyid, 
             lead__c, 
             tracking_as_of__c, 
             numberofuniqueclicks__c, 
             senddefinition__c, 
             mergeid__c, 
             triggeredsenddefinition__c, 
             sfid, 
             id, 
             _hc_lastop, 
             _hc_err,
             isarchived)
        VALUES 
            (NEW.et4ae5__dateopened__c, 
            NEW.et4ae5__numberoftotalclicks__c, 
            NEW.et4ae5__datebounced__c, 
            NEW.et4ae5__fromname__c, 
            NEW.et4ae5__hardbounce__c, 
            NEW.et4ae5__fromaddress__c, 
            NEW.et4ae5__softbounce__c, 
            NEW.name, 
            NEW.lastmodifieddate, 
            NEW.et4ae5__opened__c, 
            NEW.ownerid, 
            NEW.et4ae5__subjectline__c, 
            NEW.isdeleted, 
            NEW.et4ae5__contact__c, 
            NEW.systemmodstamp, 
            NEW.lastmodifiedbyid, 
            NEW.et4ae5__datesent__c, 
            NEW.et4ae5__dateunsubscribed__c, 
            NEW.createddate, 
            NEW.createdbyid, 
            NEW.et4ae5__lead__c, 
            NEW.et4ae5__tracking_as_of__c, 
            NEW.et4ae5__numberofuniqueclicks__c, 
            NEW.et4ae5__senddefinition__c, 
            NEW.et4ae5__mergeid__c, 
            NEW.et4ae5__triggeredsenddefinition__c, 
            NEW.sfid, 
            NEW.id, 
            NEW._hc_lastop, 
            NEW._hc_err,
            NEW.isarchived__c)
            ON CONFLICT (id) 
            DO NOTHING;

        -- Update SF to reflect the archive
        UPDATE salesforce."et4ae5__individualemailresult__c" SET isarchived__c = true, isdeleted = true WHERE id = NEW.id; 

        END IF;
        RETURN NULL;
   END;
$BODY$;

ALTER FUNCTION salesforce.archivelogicfunc()
    OWNER TO ....;

我的理解是NEW.* 只会包含导致触发器首先触发的行。因此,如果我的触发器是针对单个记录触发的,那么更新语句 NEW.id 应该只更新源表上的一条记录吗?

尝试确保触发器不会再次触发,更新语句会导致一些我不期望的递归循环。

我担心的是:

  1. 记录已更新
  2. 触发器触发并将记录插入存档表
  3. 更新在源表上运行以更新 new.id 的记录
  4. 此更新导致触发器再次运行。由于on conflict,插入会失败,但更新会再次运行,等等。

原始触发器被触发AFTER INSERT/UPDATE

触发:

CREATE TRIGGER archivelogic_firetrigger
    AFTER INSERT OR UPDATE 
    ON salesforce.et4ae5__individualemailresult__c
    FOR EACH ROW
    EXECUTE PROCEDURE salesforce.archivelogicfunc();

更新: 我在触发器中添加了WHEN 条件。它似乎适用于基本测试,但如果有建议,它愿意接受任何其他建议。

CREATE TRIGGER archivelogic_firetrigger
    AFTER INSERT OR UPDATE 
    ON salesforce.et4ae5__individualemailresult__c
    FOR EACH ROW
    WHEN (pg_trigger_depth() = 0) // <-- Added to prevent recursion 
    EXECUTE PROCEDURE salesforce.archivelogicfunc();

【问题讨论】:

    标签: postgresql database-trigger


    【解决方案1】:

    最简单的方法是将其设为before 触发器,并将更新替换为

    NEW.isarchived__c = true;
    NEW. isdeleted = true;
    [...]
    RETURN NEW;
    

    否则,您可以在运行触发器之前过滤行:仅当 isarchived__c 和 isdeleted 未更改时才会调用它(尽管这可能很危险,想象一下有人更新所有字段)

    CREATE TRIGGER archivelogic_firetrigger
    AFTER INSERT OR UPDATE 
    ON salesforce.et4ae5__individualemailresult__c
    FOR EACH ROW
    WHEN (NEW.isarchived__c IS NOT DISTINCT FROM OLD.isarchived__c 
          AND NEW.isdeleted IS NOT DISTINCT FROM OLD.isdeleted )
    EXECUTE PROCEDURE salesforce.archivelogicfunc();
    

    【讨论】:

    • 所以插入语句将保持不变,但不是编写更新语句,我可以只编写NEW.isarchived__c=trueNEW.isdeleted=true,它会更新触发器正在处理的记录?看起来我也不会返回null,而是返回NEW
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多