增加错误

时间:2011-03-30 19:19:33

标签: postgresql

如何在发生错误时抑制此表中的'id'递增?

db=> CREATE TABLE test (id serial primary key, info text, UNIQUE(info));
NOTICE:  CREATE TABLE will create implicit sequence "test_id_seq" for serial column "test.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "test_info_key" for table "test"
CREATE TABLE

db=> INSERT INTO test (info) VALUES ('hello') ;
INSERT 0 1

db=> INSERT INTO test (info) VALUES ('hello') ;
ERROR:  duplicate key violates unique constraint "test_info_key"

db=> INSERT INTO test (info) VALUES ('hello') ;
ERROR:  duplicate key violates unique constraint "test_info_key"

db=> INSERT INTO test (info) VALUES ('goodbye') ;
INSERT 0 1

db=> SELECT * from test; SELECT last_value from test_id_seq;

 id |  info   
----+---------
  1 | hello
  4 | goodbye
(2 rows)

 last_value 
------------
          4
(1 row)

4 个答案:

答案 0 :(得分:6)

你无法抑制这一点 - 而且你的ID值存在差距并没有错。

主键是一个完全没有意义的值,仅用于唯一标识表中的一行。

您不能依赖ID来永远不会有任何差距 - 只要想想如果删除一行会发生什么。

完全忽略它 - 没有错误

修改
只是想提一下,手册中也明确说明了这种行为:

  

为了避免阻止从同一序列获取数字的并发事务,从不回滚nextval操作

http://www.postgresql.org/docs/current/static/functions-sequence.html
(滚动到底部)

答案 1 :(得分:2)

您的问题归结为:“我可以从PostgreSQL序列中回滚下一个值吗?”

答案是,“你做不到。” PostgreSQL文档说

To avoid blocking concurrent transactions that obtain numbers from the same sequence, a nextval operation is never rolled back . . .

答案 2 :(得分:1)

想象一下,插入两个不同的事务。事务A获取id = 1事务B获取id = 2。交易B提交。事务A回滚。现在我们做什么?我们如何在不影响B或以后的交易的情况下回滚A的序列?

答案 3 :(得分:0)

我明白了。

我需要围绕INSERT语句编写一个包装函数。

数据库通常一次只有一个用户,因此“竞争到下一个id”的情况很少见。我关心的是当我(未提及的)“从远程数据库表中拉出行”函数尝试将不断增长的远程数据库表重新插入主数据库表时。我正在显示行ID,我不希望用户将编号中的差距视为缺少数据。

无论如何,这是我的解决方案:

CREATE FUNCTION testInsert (test.info%TYPE) RETURNS void AS '
BEGIN
  PERFORM info FROM test WHERE info=$1;
  IF NOT FOUND THEN
    INSERT INTO test (info) VALUES ($1);
  END IF;
END;' LANGUAGE plpgsql;