[英]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:三个问题:
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 Sotolongo和Belayer的帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.