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

When does a NOT NULL constraint run and can it wait until the transaction is going to commit?

我有一个 table 在 ETL 例程中一次填充一列。 强制列(外键)首先设置,因此 table 的初始状态为:

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

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

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 之前保证不为 null 并且不会被覆盖,但约束检查只是看起来在暂定插入和 table 约束条件下。

这是 PostgreSQL 的 current documented limitation,它违反了规范。

Currently, only UNIQUE, PRIMARY KEY, REFERENCES (foreign key), and EXCLUDE constraints are affected by this setting. NOT NULL and CHECK constraints are always checked immediately when a row is inserted or modified (not at the end of the statement). Uniqueness and exclusion constraints that have not been declared DEFERRABLE are also checked immediately.

您不能推迟 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).