在我的PostgreSQL 9.1数据库中,我定义了每当删除父表行时从子表中删除行的RULE。这一切都运行正常,直到我引入继承。如果来自另一个表的父(引用)表INHERITS
并且我从基表中删除然后DELETE成功,但RULE似乎根本没有触发 - 引用的行不会被删除。如果我尝试从派生表中删除,我会收到错误:
update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
父表中没有其他行会违反外键:它被被删除的行引用!我该如何解决这个问题?
以下脚本重现了该问题:
-- Schema
CREATE TABLE base
(
id serial NOT NULL,
name character varying(100),
CONSTRAINT pk_base PRIMARY KEY (id)
);
CREATE TABLE referenced
(
id serial NOT NULL,
value character varying(100),
CONSTRAINT pk_referenced PRIMARY KEY (id)
);
CREATE TABLE derived
(
referenced_id integer,
CONSTRAINT pk_derived PRIMARY KEY (id),
CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id) REFERENCES referenced (id)
)
INHERITS (base);
-- The rule
CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO derived DO ALSO
DELETE FROM referenced r WHERE r.id = old.referenced_id;
-- Some test data
INSERT INTO referenced (id, value)
VALUES (1, 'referenced 1');
INSERT INTO derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1);
-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;
-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
DELETE FROM derived
WHERE id = 2
答案 0 :(得分:1)
正如我在评论中所说,这似乎是一种不寻常的做事方式。但是你可以使用延迟约束。
CREATE TABLE derived
(
referenced_id integer,
CONSTRAINT pk_derived PRIMARY KEY (id),
CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id)
REFERENCES referenced (id) DEFERRABLE INITIALLY DEFERRED
)
INHERITS (base);
PostgreSQL文档,Rules vs. Triggers,说
也可以实现使用触发器可以完成的许多事情 使用PostgreSQL规则系统。其中一件事情不可能 规则实施的是一些约束,尤其是外来的约束 密钥。
但我不清楚这个特定的限制是你遇到的。
答案 1 :(得分:0)
此外,您还需要检查其他记录是否仍在引用要删除的行。我添加了一个测试派生记录#3,它指向相同的#1参考记录。
-- The rule
CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO tmp.derived DO ALSO (
DELETE FROM tmp.referenced re_del
WHERE re_del.id = OLD.referenced_id
AND NOT EXISTS ( SELECT * FROM tmp.derived other
WHERE other.referenced_id = re_del.id
AND other.id <> OLD.id )
;
);
-- Some test data
INSERT INTO tmp.referenced (id, value)
VALUES (1, 'referenced 1');
-- EXPLAIN ANALYZE
INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1);
INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (3, 'derived 3', 1);
-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;
-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
EXPLAIN ANALYZE
DELETE FROM tmp.derived
WHERE id = 2
;
SELECT * FROM tmp.base;
SELECT * FROM tmp.derived;
SELECT * FROM tmp.referenced;