简体   繁体   English

SELECT 级联 AFTER DELETE 触发器在 Postgres 11 中返回陈旧数据

[英]SELECT in cascaded AFTER DELETE trigger returning stale data in Postgres 11

I have an AFTER INSERT/UPDATE/DELETE trigger function which runs after any change to table campaigns and triggers an update on table contracts :我有一个AFTER INSERT/UPDATE/DELETE触发器 function 在对表campaigns进行任何更改后运行并触发表contracts的更新:

CREATE OR REPLACE FUNCTION update_campaign_target() RETURNS trigger AS $update_campaign_target$
    BEGIN
        UPDATE contracts SET updated_at = now() WHERE contracts.contract_id = NEW.contract_id;
    END;
$update_campaign_target$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS update_campaign_target ON campaigns;
CREATE TRIGGER update_campaign_target AFTER INSERT OR UPDATE OR DELETE ON campaigns
    FOR EACH ROW EXECUTE PROCEDURE update_campaign_target();

I have another trigger on table contracts that runs BEFORE UPDATE .我在运行BEFORE UPDATE的表contracts上有另一个触发器。 The goal is to generate a computed column target which displays either contracts.manual_target (if set) or SUM(campaigns.target) WHERE campaign.contract_id = NEW.contract_id .目标是生成一个计算列target ,它显示contracts.manual_target (如果设置)或SUM(campaigns.target) WHERE campaign.contract_id = NEW.contract_id

CREATE OR REPLACE FUNCTION update_contract_manual_target() RETURNS trigger AS $update_contract_manual_target$
    DECLARE
        campaign_target_count int;
    BEGIN
        IF NEW.manual_target IS NOT NULL
        THEN
            NEW.target := NEW.manual_target;
            RETURN NEW;
        ELSE
            SELECT SUM(campaigns.target) INTO campaign_target_count
                FROM campaigns
                WHERE campaigns.contract_id = NEW.contract_id;
            NEW.target := campaign_target_count;
            RETURN NEW;
        END IF;
    END;
$update_contract_manual_target$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS update_contract_manual_target ON contracts;
CREATE TRIGGER update_contract_manual_target BEFORE INSERT OR UPDATE ON contracts
    FOR EACH ROW EXECUTE PROCEDURE update_contract_manual_target();

This works as expected on INSERT and UPDATE on campaigns , but does not work on DELETE.这在campaigns的 INSERT 和 UPDATE 上按预期工作,但在 DELETE 上不起作用。 When a campaign is deleted, the result of SUM(campaigns.target) in the second trigger includes the deleted campaign's target, and thus does not update the contracts.target column to the expected value.删除活动时,第二个触发器中SUM(campaigns.target)的结果包括已删除活动的目标,因此不会将contracts.target列更新为预期值。 A second update of contracts will correctly set the value. contracts的第二次更新将正确设置该值。

Three questions:三个问题:

  1. Why doesn't this work?为什么这不起作用?
  2. Is there a way to achieve the behavior I'm looking for using triggers?有没有办法使用触发器来实现我正在寻找的行为?
  3. For this type of data synchronization, is it better to achieve this using triggers or views?对于这种类型的数据同步,是使用触发器还是视图更好地实现呢? Triggers make sense to me because this is a table that we will read many magnitudes of times more than we'll write to it, but I'm not sure what the best practices are.触发器对我来说很有意义,因为这是一张我们读取的次数比写入它的次数多很多倍的表,但我不确定最佳实践是什么。

The reason this doesn't work is the usage of NEW.contract_id in the AFTER DELETE trigger:这不起作用的原因是在AFTER DELETE触发器中使用了NEW.contract_id

UPDATE contracts SET updated_at = now() WHERE contracts.contract_id = NEW.contract_id;

Per the Triggers on Data Changes documentation, NEW is NULL for DELETE triggers.根据数据更改触发器文档,对于 DELETE 触发器,NEW 是 NULL。

Updating the code to use OLD instead of NEW fixes the issue:更新代码以使用 OLD 而不是 NEW 可以解决问题:

CREATE OR REPLACE FUNCTION update_campaign_target() RETURNS trigger AS $update_campaign_target$
    BEGIN
        IF TG_OP = 'DELETE'
        THEN
            UPDATE contracts SET updated_at = now() WHERE contracts.contract_id = OLD.contract_id;
        ELSE
            UPDATE contracts SET updated_at = now() WHERE contracts.contract_id = NEW.contract_id;
        END IF;
        RETURN NULL;
    END;
$update_campaign_target$ LANGUAGE plpgsql;

Thanks to Anthony Sotolongo and Belayer for your help!感谢Anthony SotolongoBelayer的帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM