如何更新然后插入具有唯一键约束的记录
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;
我有一个 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;