我准备了a fiddle which demonstrates the problem。
CREATE TABLE parent (
parent_id integer primary key
);
CREATE TABLE child (
child_name TEXT primary key,
parent_id integer REFERENCES parent (parent_id) ON DELETE CASCADE
);
INSERT INTO parent VALUES (1);
INSERT INTO child VALUES ('michael',1), ('vanessa', 1);
我希望删除子记录时删除CASCADE到父记录的方法 例如:
DELETE FROM child WHERE child_name='michael';
这应该级联到父表并删除记录。
答案 0 :(得分:9)
外键仅在另一个方向上工作:级联从父级删除到子级,因此当删除父级(引用的)记录时,也会删除任何子级(引用)记录。
如果它是1:1关系,您可以创建双向外键关系,其中一边是DEFERRABLE INITIALLY DEFERRED
,并且两边都是级联。
否则,您将需要子表上的ON DELETE ... FOR EACH ROW
触发器,如果没有剩余子项,则会删除父行。同时INSERT
s可能会出现竞争条件;您需要SELECT ... FOR UPDATE
父记录,然后检查其他子记录。对插入的外键检查会对引用的(父)记录执行FOR SHARE
锁定,以防止出现任何争用情况。
答案 1 :(得分:2)
你似乎想要杀死整个家庭,而不考虑剩下的孩子。运行此而不是DELETE FROM child ...
:
DELETE FROM parent p
USING child c
WHERE p.parent_id = c.parent_id
AND c.child_name='michael';
然后一切都适合您当前的设计。如果您坚持原始DELETE
声明,则需要规则或触发器。但那会很混乱。
答案 2 :(得分:0)
从你的问题和sql小提琴,你确定要删除父和所有孩子,如果一个孩子被删除?如果是这样,那么使用:
CREATE FUNCTION infanticide () RETURNS trigger AS $$
BEGIN
DELETE FROM parent WHERE parent_id = OLD.parent_id;
RETURN NULL;
END; $$ LANGUAGE plpgsql;
CREATE TRIGGER dead_kids BEFORE DELETE ON TABLE child
FOR EACH ROW EXECUTE infanticide();
您必须RETURN NULL
触发BEFORE DELETE
:您希望删除失败。原因是您删除了父级,并且该删除将级联到子表(在父表上使用适当的设置)。如果您尝试在同一语句中删除更多子项,那么您正在尝试使系统处理不存在的数据并抛弃已经消失的父项。