自动增量,但省略列中的现有值

时间:2014-03-14 14:12:20

标签: postgresql sequence auto-increment unique-constraint gaps-and-islands

我有一张桌子:

create table DB.t1 (id  SERIAL,name varchar(255));

并插入一些数据:

insert into DB.t1 (name) values ('name1');
insert into DB.t1 (id,name) values (5,'name2');
insert into DB.t1 (name) values ('name3');
insert into DB.t1 (name) values ('name4');
insert into DB.t1 (name) values ('name5');
insert into DB.t1 (name) values ('name6');
insert into DB.t1 (name) values ('name7');
select * from DB.t1;

然后我可以看到:

1 name1
5 name2
2 name3
3 name4
4 name5
5 name6   -- how to make auto-increment jump over '5'?
6 name7

但是5次出现了两次。如何保持id独特?

3 个答案:

答案 0 :(得分:4)

更新:稍后,更详细的回答:

这应该顺利进行:

CREATE OR REPLACE FUNCTION f_next_free(_seq regclass)
  RETURNS integer AS
$func$
BEGIN
   LOOP
      PERFORM nextval(_seq);
      EXIT WHEN NOT EXISTS (SELECT 1 FROM db.t1 WHERE id = lastval());
   END LOOP; 

   RETURN lastval();
END
$func$  LANGUAGE plpgsql VOLATILE;

循环从给定序列中获取下一个数字,直到找到一个尚未出现在表中的数字。甚至应该安全并发使用,因为我们仍然依赖于序列。

在串行列的默认列中使用此函数(替换串行列nextval('t1_id_seq'::regclass)的默认值:

ALTER TABLE db.t1 ALTER COLUMN id
SET DEFAULT f_next_free('t1_id_seq'::regclass);

The manual on lastval()

这适用于很少的岛屿和许多间隙(根据示例似乎是这种情况)。要强制唯一性,请在列上添加unique constraint(或主键)。

答案 1 :(得分:1)

您可以在插入时实现触发功能。如果NEW.id不为null,则此函数将生成,并更新与id字段相关的序列。

IF NEW.id IS NOT NULL THEN SELECT SETVAL(sequence_name_of_id_field,NEW.id);
END IF;

答案 2 :(得分:0)

@欧文-Brandstetter修改 首先找到丢失的值然后只需setval('t1_id_seq'::regclass, ),从而消除过多的nextval次呼叫,这会更快吗? 此外,如果问题是如何使 ids 唯一,则为默认值分配此代码不会解决问题。

我建议使用唯一约束或主键约束并处理唯一违规例外。