PostgreSQL触发器更新原始触发器运行的表。

问题描述 投票:0回答:1

在这种情况下,我有两个表。一个是我的 "热同步 "表,它是近乎实时地将数据从我的Salesforce Org同步到Postgres表的双向同步。当源系统(Salesforce)中的数据发生变化时,它会更新Postgres上的那个表。

在Postgres的这个表上,我有一个触发器,运行一些逻辑。基本上,它检查触发它的记录是否有符合某些业务逻辑的发送日期,将该行复制到另一个schematable中以 "存档"。

这一切都能正常工作。

然而我需要做的是,一旦这条记录被复制到另一个表中,我需要更新记录热同步表的状态。由于它是双向的,这将使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个回答
0
投票

最简单的就是把它做成一个 "热同步 "表。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();
© www.soinside.com 2019 - 2024. All rights reserved.