重复键值违反唯一约束且冲突不起作用

duplicate key value violates unique constraint with on conflict is not working

我正在尝试在多个字段上使用 on 与 unique 冲突。我有这个结构。

|---------------------|------------------|
|      id             |     uuid         |
|---------------------|------------------|
|      name           |     string       |
|---------------------|------------------|
|      field_a        |     uuid         |
|---------------------|------------------|
|      field_b        |     uuid         |
|---------------------|------------------|
|      field_c        |     uuid         |
|---------------------|------------------|

field_a,field_b,field_c 是唯一的,field_b 可以为 NULL。

这是我的查询:

INSERT INTO table (field_a, field_b,field_c,  name) 
values ('434d1d67-df03-4310-b3eb-93bf1c6e319e',
        'd3a3745e-ad97-4fcd-1fed-26bb406dc265',
        'd5a4232e-ad56-6ecd-5fed-25bb106dc114')
on conflict(field_a,field_b,field_c) 
do update
  set  name = 'abc'

如果我再次尝试使用相同的查询,它会起作用。它更新冲突。但是当我这样使用 null 时:

INSERT INTO 
table (field_a, field_b,field_c,  name) 
values ('434d1d67-df03-4310-b3eb-93bf1c6e319e',
        null,
        'd5a4232e-ad56-6ecd-5fed-25bb106dc114')
on conflict(field_a,field_b,field_c) 
do update
set  name = 'abc'

这不起作用。这将在我的 table 中添加新行。为了防止添加新行,我创建了一个索引并像这样设置 NULL 值

CREATE 
UNIQUE INDEX uidx_uniq ON table USING btree (
   (COALESCE(field_a, '00000000-0000-0000-0000-000000000000'::uuid)),
   (COALESCE(field_a, '00000000-0000-0000-0000-000000000000'::uuid)),
   (COALESCE(field_a, '00000000-0000-0000-0000-000000000000'::uuid)))

这不允许在 db 中添加新值(如果存在 null 值),但如果发生冲突则不起作用,它会给我错误:

duplicate key value violates unique constraint "uidx_uniq"

如何用 null 解决这个问题?

正如the documentation所说:

Null values are not considered equal.

因此,如果其中一个值为 NULL,则不会发生冲突。

您不能使用通过 ON CONFLICT 子句创建的唯一索引,因为您只能在那里使用唯一的 constraints。不能在表达式上定义唯一约束,只能在列上定义。

也许您应该使用与 NULL 不同的值,以便模拟您的意思。 NULL 在 SQL 中表示“未知”,因此 PostgreSQL 的解释是有道理的。

我想你也想要一个过滤的唯一索引:

CREATE UNIQUE INDEX uidx_uniq2 ON table (field_a, field_c)
    WHERE field_b IS NULL;

您需要检查 ON CONFLICT 中的两个索引是否存在冲突。