postgresql UPDATE ON CONFLICT查询时违反NOT NULL约束

oxalkeyp  于 5个月前  发布在  PostgreSQL
关注(0)|答案(1)|浏览(90)

我有一个表player,其中包含以下命令。我只更改了列名和顺序:

create table if not exists player (
    id varchar primary key,
    col1 boolean not null default false,
    col2 json not null default '{}',
    col3 varchar not null,
    col4 varchar not null,
    col5 json not null default '{}',
    col6 boolean not null default false
);

字符串
下面是我尝试运行的查询:

insert into player(id, col1, col2)
values (val_id, val1, val2)
on conflict(id)
do update set col1=excluded.col1, col2=excluded.col2


(存在另一个具有相同id的行,因此应该发生UPDATE
col3有一个NOT NULL约束。(我在查询之前验证了它有一个值。)然而,当查询运行时,Postgres告诉我:
错误:.关系“player”的列“col 3”中的空值违反了not-null约束
当我给col3一个默认值时,没有错误发生,所有的值都是它们应该的。
我检查了Postgres文档,但找不到查询的错误。可能是什么问题?

mepcadol

mepcadol1#

TL;DR

如果col3定义为NOT NULL而没有默认值,则INSERT * 必须 * 为其提供非空值。

深入了解

首先检查NOT NULL约束。手册:
当一个表有多个CHECK约束时,将按名称的字母顺序对每行进行测试,在检查NOT NULL约束之后。
大胆强调我的。
你可能会尝试将NOT NULL替换为普通的CHECK约束。
非空约束总是写为列约束。非空约束在功能上等效于创建检查约束CHECKcolumn_name IS NOT NULL),但在PostgreSQL中创建显式非空约束更有效。缺点是您不能为以这种方式创建的非空约束提供给予显式名称。
但是没有用。任何一个约束都是立即检查的,不能推迟。手册:

NOT NULLCHECK约束总是在插入或修改行时立即检查(而不是在语句的末尾)。

大胆强调我的。
这是核心问题。
执行以下操作之一来解决:
1.为col3定义非空列默认值。
(如果您知道自己在做什么,可以添加一个BEFORE INSERT触发器来执行更复杂的魔术。
1.删除NOT NULL约束。
1.在INSERT中为col3提供一个非空值。您可以在UPDATE中应用或删除相同的值。例如:

INSERT INTO player(id, col1, col2, col3)  -- !
VALUES (val_id, val1, val2, val3)         -- !
ON     CONFLICT (id) DO UPDATE
SET    col1 = excluded.col1
     , col2 = excluded.col2
--   , col3 = excluded.col3               -- optional
;

字符串
(The这同样适用于您添加的表定义中的col4

相关问题