错误时递增

发布于 2024-10-29 10:01:01 字数 961 浏览 1 评论 0原文

当发生错误时,如何抑制该表中的“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)

How do I suppress the 'id' in this table from incrementing when an error occurs?

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

独自唱情﹋歌 2024-11-05 10:01:01

您不能抑制这一点 - 在ID值中差距没有错。

主键是一个完全毫无意义的值,仅用于唯一识别表中的一行。

您不能依赖 ID 永远不会有任何间隙 - 试想一下如果删除一行会发生什么。

简单地忽略它 - 没有什么错

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

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

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

You cannot suppress this - and there is nothing wrong with having gaps in your ID values.

The primary key is a totally meaningless value that is only used to uniquely identify one row in a table.

You cannot rely on the ID to never have any gaps - just think what happens if you delete a row.

Simply ignore it - nothing is wrong

Edit
Just wanted to mention that this behaviour is also clearly stated in the manual:

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

http://www.postgresql.org/docs/current/static/functions-sequence.html
(Scroll to the bottom)

最冷一天 2024-11-05 10:01:01

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

答案是:“你不能。” PostgreSQL 文档说

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

Your question boils down to this: "Can I rollback the next value from a PostgreSQL sequence?"

And the answer is, "You can't." PostgreSQL documentation says

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

寄居人 2024-11-05 10:01:01

想象一下两个不同的事务要插入。事务 A 获取 id=1 事务 B 获取 id=2。事务 B 提交。事务A回滚。现在我们该怎么办?如何回滚 A 的序列而不影响 B 或后续事务?

Imagine two different transactions go to insert. Transaction A gets id=1 Transaction B gets id=2. Transaction B commits. transaction A rolls back. Now what do we do? How could we roll back the sequence for A without affecting B or later transactions?

不疑不惑不回忆 2024-11-05 10:01:01

我想通了。

我需要围绕 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;

I figured it out.

I needed to write a wrapper function around my INSERT statement.

The database will normally have one user at a time so the 'race to the next id' condition is rare. What I was concerned about was when my (unmentioned) 'pull rows from remote database table' function would try to reinsert the growing remote database table into the master database table. I am displaying the row ids and I didn't want the users to see the gap in numbering as missing data.

Anyways here is my solution:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文