具有空约束值的Postgres UPSERT行不起作用

时间:2020-09-04 19:16:18

标签: postgresql constraints upsert

我正在尝试编写一个存储过程,即使键中的值之一为空,我也可以在其中插入一行。我阅读了文档,发现Postgres不能用于比较相等的空值。

我还阅读了其他论坛帖子,并注意到我想要实现的目标可以通过部分索引来完成。我能够成功地违反约束,但是当我传递生日为空的值时,我的“冲突中”就不会被击中。

我希望能够传递一个空生日,即使一个人的生日为空,也可以更新其ID。

(
    id bigint not null,
    name text,
    birthday date
);

我创建了索引和部分索引,以使生日可以为空

CREATE UNIQUE INDEX name_birthday_key on people (name, birthday);
CREATE UNIQUE INDEX birthday_null_key on people (name) where birthday is null;
create or replace procedure store_person(_identifier bigint, _name character varying, _birthday date)
    language plpgsql
as
$$
begin
   insert into people (
    id, name, birthday
    )
    values (
    _identifier, _name, _birthday
    )
    on conflict (name, birthday)
    do update
    set
        id = _identifier
        where people.birthday = _date and people.name = _name;
end
$$;

如果我跑步:

call public.store_person(1, 'Bob', '1955-01-09')
call public.store_person(2, 'Bob', '1955-01-09')

我成功地看到数据库中唯一的行是ID为2的Bob。 但是,如果我跑步

call public.store_person(3, 'Joe', null)
call public.store_person(4, 'Joe', null)

我得到的唯一行是ID3。ID4的第二个插入从未更新现有行。我确实收到违规错误,但从未点击“冲突时”更新。

有人可以指出正确的方向吗?

1 个答案:

答案 0 :(得分:1)

CONFLICT不匹配,因为NULL不等于NULL。这不是PostgreSQL,而是在SQL标准中定义的。

插入数据时,请使用COALESCE(birthday, '0001-01-01')之类的东西,它们会匹配;并删除部分索引。

您的代码有一个错误,在DO UPDATE...WHERE中:没有名为_date的名称,应为_birthday