什么时候运行NOT NULL约束并且它可以等到事务要提交?

时间:2017-04-18 23:03:45

标签: postgresql sqlalchemy notnull

我有一个表在ETL例程期间一次填充一列。 必需列(外键)首先设置,因此表的初始状态为:

key    | fkey   | a
-------|--------|-------
1      | 1      | null

在处理A值之后,我使用SQL Alchemy和PostgreSQL方言插入它们进行简单的upsert:

upsert = sqlalchemy.sql.text("""
    INSERT INTO table
      (key, a)
    VALUES (:key, :a)
    ON CONFLICT (key) DO UPDATE SET
      a = EXCLUDED.a
""")

但是这失败了,因为它显然试图将fkey值插入null

psycopg2.IntegrityError: null value in column "fkey" violates not-null constraint
DETAIL:  Failing row contains (1, null, 0).

语法是否正确?它为什么失败? SQLAlchemy是否参与此错误或是否正确翻译PLSQL?

我怀疑约束检查是在CONFLICT解决方案触发之前发生的,所以虽然它实际上可行,因为fkey保证在之前不为空并且不会被覆盖,但约束检查仅查看暂定插入和表约束。

1 个答案:

答案 0 :(得分:4)

这是PostgreSQL的current documented limitation,它打破了规范。

  

目前,此设置仅影响UNIQUE,PRIMARY KEY,REFERENCES(外键)和EXCLUDE约束。 插入或修改行时不会立即检查NOT NULL和CHECK约束(不在语句末尾)。还会立即检查尚未声明为DEFERRABLE的唯一性和排除约束。

您无法推迟NOT NULL约束,而且您似乎了解默认行为,如此处所示。

CREATE TABLE foo ( a int NOT NULL, b int UNIQUE, c int );
INSERT INTO foo (a,b,c) VALUES (1,2,3);

INSERT INTO foo (b,c) VALUES (2,3);
ERROR:  null value in column "a" violates not-null constraint
DETAIL:  Failing row contains (null, 2, 3).