设置约束所有DEFERRED在PostgreSQL 9.3中没有按预期工作

use*_*074 12 sql postgresql database-design referential-integrity foreign-keys

如果我定义表ab如下:

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);
Run Code Online (Sandbox Code Playgroud)

然后执行以下操作:

START TRANSACTION;
SET CONSTRAINTS ALL DEFERRED;
INSERT INTO b(j) VALUES(2);
INSERT INTO a(i) VALUES(2);
COMMIT;
Run Code Online (Sandbox Code Playgroud)

它产生以下错误.为什么SET CONSTRAINTS没有达到预期的效果?

错误:表"b"上的插入或更新违反外键约束"fkey_ij"
SQL状态:23503详细信息:表"a"中不存在键(j)=(2).

Erw*_*ter 12

对于初学者来说,只能DEFERRABLE推迟约束.

但是,这不会帮助你的情况,因为,FK约束不能这样弯曲可言.每个文件:

NO ACTION即使约束被声明为可延迟,也不能推迟除检查之外的引用操作.

颠倒INSERT语句的顺序.

有关:

  • 如果外键约束不能受到`SET CONSTRAINTS`的影响,那么为什么要做`SET CONSTRAINTS`状态的文档:"当前,只有UNIQUE,PRIMARY KEY,**REFERENCES(外键)**和EXCLUDE约束受此设置的影响"?http://www.postgresql.org/docs/current/static/sql-set-constraints.html (4认同)
  • 没关系,想通了.它们可能受到影响,但前提是你没有使用"ON UPDATE"或"ON DELETE"动作,在这种情况下是OP. (2认同)

Ale*_*ore 5

我同意其他人的观点,即正确的方法是按正确的顺序 - 但有时这不是一个可行的选择,需要更简单的方法才能在时间预算内完成工作。

如果这对任何人有帮助,我制作了一个程序,可以自动将延迟选项添加到所有 FK,以便

将所有约束设置为推迟;

命令将会起作用。当然,仅在必要时使用它。

DO
$$
DECLARE
    temp_rec RECORD;
    sql_exe TEXT;
BEGIN

sql_exe := $sql$
ALTER TABLE %1$s ALTER CONSTRAINT %2$s DEFERRABLE;
$sql$
;

FOR temp_rec IN 

(select constraint_name, table_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY')

LOOP
    EXECUTE format(sql_exe, temp_rec.table_name, temp_rec.constraint_name);
END LOOP;

END;
$$
LANGUAGE plpgsql
;
Run Code Online (Sandbox Code Playgroud)