在PostgreSQL 9.3数据库中,如果我按以下方式定义表a
和b
:
CREATE TABLE a(i integer);
ALTER TABLE a ADD CONSTRAINT pkey_a PRIMARY KEY (i);
CREATE TABLE b(j integer);
ALTER TABLE b add CONSTRAINT fkey_ij FOREIGN KEY (j)
REFERENCES a (i) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;
INSERT INTO a(i) VALUES(1);
然后执行以下操作:
START TRANSACTION;
SET CONSTRAINTS ALL DEFERRED;
INSERT INTO b(j) VALUES(2);
INSERT INTO a(i) VALUES(2);
COMMIT;
它会产生以下错误。为什么SET CONSTRAINTS
效果不理想?
ERROR: insert or update on table "b" violates foreign key constraint "fkey_ij" SQL state: 23503 Detail: Key (j)=(2) is not present in table "a".
仅DEFERRABLE
约束可以延迟。
让我先提出更好的选择:
INSERT
顺序反转INSERT
语句的顺序,无需延迟任何操作。最简单,最快-可能的话。
用单个命令]执行。然后,仍然不需要推迟任何操作,因为检查了[[每个命令后]]的非延迟约束,并且将CTE视为单个命令的一部分:WITH ins1 AS (
INSERT INTO b(j) VALUES(2)
)
INSERT INTO a(i) VALUES(2);
同时,您可以重用第一个INSERT
的值;对于某些情况或多行插入,更安全/更方便:
WITH ins1 AS ( INSERT INTO b(j) VALUES(3) RETURNING j ) INSERT INTO a(i) SELECT j FROM ins1;
但是我需要推迟约束! (真的吗?)
ALTER TABLE b ADD CONSTRAINT fkey_ij FOREIGN KEY (j) REFERENCES a (i) MATCH SIMPLE ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; -- !!!
然后您的原始代码有效(速度较慢,因为延迟的约束会增加成本)。相关:db <>小提琴here
NO ACTION
检查以外的其他参考动作不能被推迟,即使约束被声明为可延期。
但是那是令人误解的,因为它仅适用于“引用动作”,即,ON UPDATE
或ON DELETE
对被引用表中的行会发生什么。当前的情况不是其中一种-如@zer0hedge pointed out。