假设存在以下表和触发器:
CREATE TABLE "event"
(
count bigserial NOT NULL,
action text NOT NULL,
child_id int NOT NULL,
persisted_field text NULL,
CONSTRAINT "event_pkey" PRIMARY KEY (count)
);
CREATE TABLE "parent_table"
(
id int PRIMARY KEY,
field_to_persist text
);
CREATE TABLE "child_table"
(
id int PRIMARY KEY,
parent_id int,
CONSTRAINT "child_parent_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "parent_table" ("id") ON DELETE CASCADE
);
CREATE OR REPLACE FUNCTION add_child_trigger() RETURNS TRIGGER AS
$$
DECLARE
v_id int = coalesce(new.id, old.id);
v_parent_id int = coalesce(new.parent_id, old.parent_id);
BEGIN
INSERT INTO "event" ("action", "child_id", "persisted_field")
VALUES (tg_op, v_id,
(SELECT "parent_table"."field_to_persist" FROM "parent_table" WHERE "parent_table"."id" = v_parent_id));
IF (tg_op = 'DELETE') THEN
RETURN OLD;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "on_change_add_change_event"
BEFORE INSERT OR UPDATE OR DELETE
ON "child_table"
FOR EACH ROW
EXECUTE PROCEDURE "add_child_trigger"();
执行以下语句:
INSERT INTO "parent_table" VALUES (1, 'something');
INSERT INTO "child_table" VALUES (1, 1);
INSERT INTO "child_table" VALUES (2, 1);
DELETE FROM "child_table" WHERE "id" = 2;
DELETE FROM "parent_table" WHERE "id" = 1;
event
表现在包含以下记录:
| 计数|行动|子ID|持续字段|
| --|--|--|--|
| 1 |插入| 1 |东西|
| 2 |插入| 2 |东西|
| 3 |删除| 2 |东西|
| 4 |删除| 1 |null|
但是,与通过删除parent_table
所指向的记录来级联删除child_table
的条目相比,persisted_field
在单独删除child_table
的条目时为空。为什么persisted_field
null
与count
4记录在一起,我如何将触发器更改为something
?
1条答案
按热度按时间njthzxwz1#
为什么
persisted_field
null
与count
4一起记录触发器按预期触发
before delete on child_table
,但在级联场景中,parent_table
上的delete
完成 * 之后 * 仍然会发生,因此这个子查询什么也没有找到:(demo)当您到达此语句时,您可能希望此语句查找的
"parent_table"."id"
已经被删除。Chapter 39. Triggers:在行级
BEFORE
触发器中执行的SQL命令 * 将 * 看到先前在同一外部命令中处理的行的数据更改的影响。这涉及到目标表以及任何其他受命令直接或间接影响的对象中的更改(通过级联和触发器,以及生成的列,规则或例程副作用)。
没有办法延迟
parent_table
行的删除,以便当delete
级联到链接的child_table
行时,它仍然可以被随后触发的触发器看到。关于CREATE TRIGGER
:由外键强制操作(如
ON UPDATE CASCADE
或ON DELETE SET NULL
)导致的行更新或删除被视为导致它们的SQL命令的一部分(注意此类操作永远不会延迟)。第二(部分)问题:
如何将触发器更改为
something
?创建另一个并将其附加到
parent_table
。确保child_table
上的条目不会重复它的工作,最终从parent_table
触发器得到一个event
条目,然后从child_table
得到另一个条目。before delete on "parent_table"
触发器可以创建一个临时条目:demo然后
child_table
上的触发器仍然可以看到它,并使用coalesce()
及其当前查找的结果。之后,子触发器可以擦除临时条目您可能还需要考虑将
ON UPDATE CASCADE
添加到child_parent_id_fkey
以涵盖这种情况。否则,对parent_table.id
的更改会引发错误:demo