繁体   English   中英

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

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

我有一个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();

我在运行BEFORE UPDATE的表contracts上有另一个触发器。 目标是生成一个计算列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();

这在campaigns的 INSERT 和 UPDATE 上按预期工作,但在 DELETE 上不起作用。 删除活动时,第二个触发器中SUM(campaigns.target)的结果包括已删除活动的目标,因此不会将contracts.target列更新为预期值。 contracts的第二次更新将正确设置该值。

三个问题:

  1. 为什么这不起作用?
  2. 有没有办法使用触发器来实现我正在寻找的行为?
  3. 对于这种类型的数据同步,是使用触发器还是视图更好地实现呢? 触发器对我来说很有意义,因为这是一张我们读取的次数比写入它的次数多很多倍的表,但我不确定最佳实践是什么。

这不起作用的原因是在AFTER DELETE触发器中使用了NEW.contract_id

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

根据数据更改触发器文档,对于 DELETE 触发器,NEW 是 NULL。

更新代码以使用 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;

感谢Anthony SotolongoBelayer的帮助!

暂无
暂无

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

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