![](/img/trans.png)
[英]Function and trigger of postgresql to update in a table the changes that take place in another one
[英]PostgreSQL: Trigger Function bypasses trigger of another table
有两个表:gc_res 和anchor。 锚表有一个唯一的键——anchor_id。
当数据到达 gc_res 时,res_eval 触发器被触发,数据被 gc_res_eval() 部分评估。 一些条目保留下来,其他条目通过插入到锚表中被推送。 锚表在插入之前有一个触发器,它也预先评估数据并接受插入或更新旧条目。 在后一种情况下,它可能会另外写入第三个(日志)表。
两个触发器看起来相同:
CREATE TRIGGER res_eval BEFORE INSERT ON gc_res
FOR EACH ROW EXECUTE PROCEDURE gc_res_eval();
CREATE TRIGGER anchor_smart_insert BEFORE INSERT ON anchor
FOR EACH ROW EXECUTE PROCEDURE anchor_smart_insert();
当我直接尝试写入锚表时,anchor_smart_insert 触发器正确触发并且工作正常。 尝试插入数据的 gc_res_eval 部分使用 CTE:
WITH anchor_insert AS (
INSERT INTO cbm.anchor (anchor_id, pin, geo, rwo, rwo_value, addr) (
SELECT osm_id, pin, geo, rwo, rwo_value, addr FROM gc_eval
WHERE similarity > accept_polygon AND geo_type = 'Polygon'
) RETURNING anchor_id
) SELECT array_agg(anchor_id) FROM anchor_insert INTO anchors
;
当 gc_res_eval 尝试插入锚表并且 anchor_id 没有冲突时 - 一切正常。 如果存在冲突,则在唯一约束上插入失败。 因此我假设 - 第二个触发器不会触发。
CREATE OR REPLACE FUNCTION anchor_smart_insert()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
geog geography;
acceptable_intersect int := 10;
acceptable_overlap_index NUMERIC := 0.56;
BEGIN
SELECT INTO geog geo FROM cbm.anchor a
WHERE a.anchor_id=NEW.anchor_id;
RAISE NOTICE 'anchor_smart_insert is running';
IF ST_Area(ST_Intersection(geog, NEW.geo))>acceptable_intersect THEN
UPDATE cbm.anchor a SET
pin=COALESCE(NEW.pin, ST_Centroid(NEW.geo)),
geo=NEW.geo,
rwo=NEW.rwo,
rwo_value=NEW.rwo_value,
addr=NEW.addr
WHERE a.anchor_id=NEW.anchor_id AND (
a.geo IS DISTINCT FROM NEW.geo
OR a.rwo IS DISTINCT FROM NEW.rwo
OR a.rwo_value IS DISTINCT FROM NEW.rwo_value
OR a.addr IS DISTINCT FROM NEW.addr);
INSERT INTO cbm.anchor_history (anchor_id, geo) VALUES (NEW.anchor_id, geog);
IF ST_Area(ST_Intersection(geog, NEW.geo))^2/(ST_Area(geog)*ST_Area(NEW.geo))<acceptable_overlap_index THEN
INSERT INTO cbm.anchor_review(anchor_id, geo, rwo, rwo_value, addr) VALUES
(NEW.anchor_id, NEW.geo, NEW.rwo, NEW.rwo_value, NEW.addr);
END IF;
RETURN NULL;
END IF;
RETURN NEW;
END;
$function$
;
DBMS 是一个 pg11 AWS RDS。
责备自己:只要比较的多边形大于 10 平方米,anchor_smart_insert() 函数就可以正常工作。 有一个假设,应该只有两个选择:大于 10 平方米,或者空。
根据这样的逻辑推理,删除了包含所有豁免的部分,因为它似乎没有必要。
这也是为什么通过直接插入进行的测试效果很好:多边形大于 10 平方米并导致更新。
谢谢@Adrian Klaver - 您的建议有帮助!
恢复/改进的功能以某种方式正确处理 <10 平方米的多边形,它将其与初始和最终尺寸进行预先比较 - 如果它们更小,则需要更安全的值。 此外,它还明确处理可能的插入(现有的 anchor_id ISNULL)。
CREATE OR REPLACE FUNCTION cbm.anchor_smart_insert()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
geog geography;
acceptable_intersect NUMERIC:= 10;
acceptable_overlap_index NUMERIC := 0.56;
BEGIN
SELECT INTO geog geo FROM cbm.anchor a
WHERE a.anchor_id=NEW.anchor_id;
IF geog ISNULL THEN RETURN NEW; END IF;
IF ST_Area(ST_Intersection(geog, NEW.geo))>LEAST(acceptable_intersect, GREATEST(ST_Area(geog), ST_Area(NEW.geo))) THEN
UPDATE cbm.anchor a SET
pin=COALESCE(NEW.pin, ST_Centroid(NEW.geo)),
geo=NEW.geo,
rwo=NEW.rwo,
rwo_value=NEW.rwo_value,
addr=NEW.addr
WHERE a.anchor_id=NEW.anchor_id AND (
a.geo IS DISTINCT FROM NEW.geo
OR a.rwo IS DISTINCT FROM NEW.rwo
OR a.rwo_value IS DISTINCT FROM NEW.rwo_value
OR a.addr IS DISTINCT FROM NEW.addr);
IF ST_Area(ST_Intersection(geog, NEW.geo))^2/(ST_Area(geog)*ST_Area(NEW.geo))<acceptable_overlap_index THEN
INSERT INTO cbm.anchor_history (anchor_id, geo) VALUES (NEW.anchor_id, geog);
END IF;
END IF;
-- bad intersection:
INSERT INTO cbm.anchor_review(anchor_id, geo, rwo, rwo_value, addr) VALUES
(NEW.anchor_id, NEW.geo, NEW.rwo, NEW.rwo_value, NEW.addr);
RETURN NULL;
END;
$function$
;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.