48

我的目标是在表中插入新行时自动插入主键字段。

如何在 PostgreSQL 中获取从会话到会话的序列?

 doubleemploi@hanbei:/home/yves$ psql -d test
 Mot de passe : 
 psql (8.4.13)
 Saisissez « help » pour l''aide.

 test=> create sequence test001 start 10;
 CREATE SEQUENCE
 test=> select currval('test001');
 ERREUR:  la valeur courante (currval) de la séquence « test00 » n''est pas encore définie dans cette session
 --- current value not yet defined this session (???)
 test=> select setval('test001', 10);
 setval 
 --------
      10
 (1 ligne)

 test=> select currval('test00');
  currval 
 ---------
       10
 (1 ligne)

 test=> \q
 test@hanbei:/home/yves$ psql -d test
 Mot de passe : 
 psql (8.4.13)
 Saisissez « help » pour l''aide.

 test=> select currval('test001');
 ERREUR:  la valeur courante (currval) de la séquence « test00 » n''est pas encore définie dans cette session
4

5 回答 5

135

currval返回为当前会话中的序列生成的最后一个值。因此,如果另一个会话为该序列生成一个新值,您仍然可以检索您的会话生成的最后一个值,从而避免错误。

但是,要在任何会话中获取最后生成的值,您可以使用上面的:

SELECT last_value FROM your_sequence_name;

请注意,如果该值被其他会话与未提交(或中止)事务使用,并且您将此值用作参考,则可能会出现错误。即使在得到这个值之后,它也可能已经过时了。一般人只currval需要setval.

于 2012-09-18T18:18:32.657 回答
20

这可能比你想象的要简单......

我的目标是在表中插入新行时自动插入主键字段。

只需设置列的默认值:

ALTER TABLE tbl ALTER COLUMN tbl_id SET DEFAULT nextval('my_seq'::regclass);

或者更简单,创建一个serial主键类型的表:

CREATE TABLE tbl(
  tbl_id serial PRIMARY KEY
 ,col1 txt
  -- more columns
);

它创建一个专用序列并tbl_id自动设置默认值。

在 Postgres 10 或更高版本中,请考虑使用IDENTITY列。看:

如果tbl_id您没有在INSERT. 适用于任何会话,并发与否。

INSERT INTO tbl(col1) VALUES ('foo');

如果你想让新的tbl_id背对它做点什么:

INSERT INTO tbl(col1) VALUES ('foo') RETURNING tbl_id;
于 2012-09-18T22:35:13.560 回答
13

对于这个问题,我会给出一个实际的答案。我的程序和 psql 终端使用我的数据库服务器;所以有多个会话。目前我在我的 psql 终端中:

fooserver=> select currval('fusion_id_seq');
ERROR:  currval of sequence "fusion_id_seq" is not yet defined in this session
fooserver=> select nextval('fusion_id_seq');
 nextval 
---------
  320032
(1 row)

fooserver=> select currval('fusion_id_seq');
 currval 
---------
  320032
(1 row)

看起来您只能在自己的会话中看到值。这也会影响另一个会话的currval。这可能与服务器的多线程隔离不同的会话有关。计数器(psql 中的串行)是一个共享对象。在我看来,只要计数器被正确锁定以确保只有单个线程(会话)可以增加它(原子操作),这个会话应该能够获取计数器的当前值。但我在这里可能是错的(不是数据库服务器编写器的专家)。

于 2017-12-05T23:59:10.150 回答
4

实际上nextval将推进序列并返回新值,这将是您问题的答案。

currval 将返回最近使用 nextval 获得的指定序列的值(如果当前会话中没有使用 nextval,这可能会失败)。

于 2016-01-12T16:12:32.850 回答
1

这个问题似乎是间歇性的,为了保持一致性,请使用 CTE 获取当前会话的插入序列

WITH inserted AS ( 
         INSERT INTO notifn_main (notifn_dt,stat_id)
     SELECT now(),22 
     FROM notifn 
     RETURNING id )
     SELECT id 
     from inserted INTO tmp_id;
于 2017-08-30T20:30:31.693 回答