如何更新然后插入具有唯一键约束的记录

how to update and then insert a record with unique key constraint

我有一个 table,其中 a、b、c 和 c 列具有唯一键约束。

a |b |c(uk)
----------
aa 1  z

我想插入一个值为 (bb,1,z) 的新行,如果 z 已经存在,那么我首先想将现有行更新为

a |b |c(uk)
----------
aa 1  null

然后插入(bb,1,z),使最后的行如下图所示。

a |b |c(uk)
----------
aa 1  null
bb 1  z

我如何通过一个 sql 语句完成此操作?

我认为你应该为此使用 BEFORE INSERT TRIGGER

在触发器中,您将更新所有包含值 new.c 的记录,例如:

UPDATE my_table SET
  c = NULL
WHERE 
  c = new.c;

如果 c 不存在 - 什么都不会发生。

如果 2 个并发事务向 c 中插入相同的值,您仍然可能 运行 进入唯一约束违规错误。为避免这种情况,您可以使用 advisory locks 从 c.

的值提供锁定 ID

不幸的是,在 Postgres 中每行检查唯一约束 - 除非它们被创建为“可延迟”。

因此,如果您想在单个语句中执行 UPDATE 和 INSERT,则必须重新创建具有可延迟属性的唯一约束。然后 Postgres 将在 语句 .

的末尾检查它
create table the_table 
(
  a text, 
  b int, 
  c text
);

alter table the_table 
    add constraint unique_c 
    unique(c)
    deferrable --<< this is the "magic"
;

然后你可以用 data modifying CTE

with input (a,b,c) as (
  values ('bb', 1, 'z')
), change_old as (
  update the_table
  set c = null
  from input
  where input.c = the_table.c
)  
insert into the_table
select a,b,c
from input;