发生插入冲突时如何不增加序列
How to not increment sequence when conflict of insert occurs
当插入到具有自动递增 id 列的 table 时发生冲突时,序列会发生碰撞,导致 id 范围出现间隙,这对我来说是不可取的。
这是我的情况的简化版本:
create table tab1 (
id serial,
col1 int,
col2 int,
col3 int,
constraint const1 unique (col1, col2)
);
在存储过程中:
insert into tab1 (col1, col2, col3)
values (1, 2, 3)
on conflict on constraint const1
do update set col3 = excluded.col3
如果发生冲突,insert ... on conflict ... update
工作正常,除了序列中的下一个值被烧毁。
如果不先进行 exists()
检查,是否有办法 不 只使用一条语句从序列中刻录下一个值?
注意:不会出现针对同一冲突键的并发更新的竞争条件。
无法避免序列递增,因为它发生在检测到冲突之前。
这是我使用的解决方法:
insert into tab1 (col1, col2, col3)
select x.*
from (select 1 a, 2 b, 3 c) x
left join tab1 o on o.col1 = x.a and o.col2 = x.b
where o.col1 is null
returning tab1.id into _id;
if _id is null then
update tab1 set
col3 = 3
where col1 = 1
and col2 = 2;
end if;
当插入到具有自动递增 id 列的 table 时发生冲突时,序列会发生碰撞,导致 id 范围出现间隙,这对我来说是不可取的。
这是我的情况的简化版本:
create table tab1 (
id serial,
col1 int,
col2 int,
col3 int,
constraint const1 unique (col1, col2)
);
在存储过程中:
insert into tab1 (col1, col2, col3)
values (1, 2, 3)
on conflict on constraint const1
do update set col3 = excluded.col3
如果发生冲突,insert ... on conflict ... update
工作正常,除了序列中的下一个值被烧毁。
如果不先进行 exists()
检查,是否有办法 不 只使用一条语句从序列中刻录下一个值?
注意:不会出现针对同一冲突键的并发更新的竞争条件。
无法避免序列递增,因为它发生在检测到冲突之前。
这是我使用的解决方法:
insert into tab1 (col1, col2, col3)
select x.*
from (select 1 a, 2 b, 3 c) x
left join tab1 o on o.col1 = x.a and o.col2 = x.b
where o.col1 is null
returning tab1.id into _id;
if _id is null then
update tab1 set
col3 = 3
where col1 = 1
and col2 = 2;
end if;