[英]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
的第二次更新将正确设置该值。
三个问题:
这不起作用的原因是在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 Sotolongo和Belayer的帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.