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

时间:2019-01-28 08:27:47

标签: sql postgresql null unique-index

我正在尝试在多个字段上使用唯一性冲突。我有这个结构。

|---------------------|------------------|
|      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'

这不起作用。这将在我的表中添加新行。为了防止添加新行,我创建了一个索引并设置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来解决这个问题?

2 个答案:

答案 0 :(得分:0)

the documentation说:

  

空值不视为相等。

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

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

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

答案 1 :(得分:0)

我认为您还需要过滤的唯一索引:

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

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