PostgreSQL Триггер, обновляющий таблицу, откуда запускается исходный триггер - PullRequest
0 голосов
/ 07 мая 2020

В этом сценарии у меня две таблицы. Одна из них - моя таблица «горячей синхронизации c», которая представляет собой двунаправленную синхронизацию c данных из моей организации Salesforce с таблицей Postgres почти в реальном времени. По мере изменения данных в исходной системе (Salesforce) эта таблица обновляется на Postgres.

В этой таблице в Postgres у меня есть триггер, который запускает некоторые logi c. Он в основном проверяет, имеет ли инициирующая запись дату отправки, которая соответствует некоторому бизнес-логу c, копирует эту строку в другую схему / таблицу, чтобы «заархивировать» ее.

Все это работает нормально.

Что мне нужно сделать, так это после того, как эта строка будет скопирована в другую таблицу, мне нужно обновить статус таблицы горячей синхронизации c записи. Поскольку он двунаправленный, это позволит данным в 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 должен обновлять только одну запись в исходной таблице? какой-то рекурсивный l oop, которого я не ожидал.

Меня беспокоит:

  1. Запись обновлена ​​
  2. Триггер срабатывает и вставляет запись в архивную таблицу
  3. В исходной таблице выполняется обновление для обновления записи для new.id
  4. Это обновление вызывает повторный запуск триггера. Вставка не удалась из-за on conflict, но затем обновление запустилось бы снова, и снова et c ..

Срабатывает исходный триггер AFTER INSERT/UPDATE.

ТРИГГЕР:

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

ОБНОВЛЕНИЕ: Я добавил в свой триггер условие WHEN. Похоже, что он работал на базовом c тесте, но готов принять любой другой совет, если предложат.

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();

1 Ответ

0 голосов
/ 07 мая 2020

Проще всего сделать его триггером 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();
...