postgreSQL函数为最后插入的ID

我如何获得插入到表中的最后一个ID? 在MS SQL中有SCOPE_IDENTITY()。

请不要build议使用这样的东西:

select max(id) from table 

tl;dr :goto选项3:INSERT和RETURNING)

回想一下,在postgresql中,表没有“id”的概念,只是序列 (通常,但不一定用作替代主键的默认值,带有SERIAL伪types)。

如果您有兴趣获取新插入的行的ID,有几种方法:


选项1: CURRVAL(<sequence name>);

例如:

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John'); SELECT currval('persons_id_seq'); 

序列的名称必须是已知的,它是任意的; 在这个例子中,我们假设表persons有一个用SERIAL伪types创build的id列。 为了避免依赖这个,并感觉更干净,你可以使用pg_get_serial_sequence

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John'); SELECT currval(pg_get_serial_sequence('persons','id')); 

警告: currval()只能在同一个会话中INSERT (已经执行nextval() )之后工作


选项2: LASTVAL();

这与前面的类似,只是不需要指定序列名称:它会查找最近修改的序列(总是在您的会话中,与上面相同的警告)。


CURRVALLASTVAL都是完全并发的安全。 序列在PG中的行为被devise成不同的会话不会干扰,所以不存在竞争条件的风险(如果另一个会话在我的INSERT和SELECT之间插入另一行,我仍然得到我的正确值)。

但是他们确实有一个微妙的潜在问题。 如果数据库有一些TRIGGER (或RULE),在插入到persons表中时,在其他表中插入一些额外的插入…然后LASTVAL可能会给我们错误的值。 这个问题甚至可能发生在CURRVAL ,如果额外的插入是在同一persons表中完成的(这是不常见的,但风险依然存在)。


选项3: INSERT

 INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id; 

这是获得ID最干净,最有效和最安全的方式。 它没有任何以前的风险。

缺点? 几乎没有:您可能需要修改您调用INSERT语句的方式(在最糟糕的情况下,可能您的API或DB层不希望INSERT返回值); 这不是标准的SQL(谁在乎); 它从Postgresql 8.2(Dec 2006 …)


结论:如果可以,请select3.在其他地方,更喜欢1。

注意:如果您打算获取最后一个全局插入的ID (不一定在您的会话中),所有这些方法都是无用的。 为此,您必须求助于select max(id) from table (当然,这不会读取来自其他事务的未提交插入)。

请参阅INSERT语句的RETURNING子句。 基本上,INSERT加倍作为一个查询,并返回插入的值。

您可以在INSERT语句中使用RETURNING子句,如下所示

 wgzhao=# create table foo(id int,name text); CREATE TABLE wgzhao=# insert into foo values(1,'wgzhao') returning id; id ---- 1 (1 row) INSERT 0 1 wgzhao=# insert into foo values(3,'wgzhao') returning id; id ---- 3 (1 row) INSERT 0 1 wgzhao=# create table bar(id serial,name text); CREATE TABLE wgzhao=# insert into bar(name) values('wgzhao') returning id; id ---- 1 (1 row) INSERT 0 1 wgzhao=# insert into bar(name) values('wgzhao') returning id; id ---- 2 (1 row) INSERT 0 

Leonbloy的答案相当完整。 我只会添加一个特殊情况,其中一个需要从PL / pgSQL函数中获取最后插入的值,其中OPTION 3不完全适合。

例如,如果我们有以下表格:

 CREATE TABLE person( id serial, lastname character varying (50), firstname character varying (50), CONSTRAINT person_pk PRIMARY KEY (id) ); CREATE TABLE client ( id integer, CONSTRAINT client_pk PRIMARY KEY (id), CONSTRAINT fk_client_person FOREIGN KEY (id) REFERENCES person (id) MATCH SIMPLE ); 

如果我们需要插入客户logging,我们必须参考一个人的logging。 但是,假设我们想要devise一个PL / pgSQL函数来插入一个新的logging到客户端,但是也会考虑插入新的人员logging。 为此,我们必须略微改变leonbloy的scheme3:

 INSERT INTO person(lastname, firstname) VALUES (lastn, firstn) RETURNING id INTO [new_variable]; 

请注意,有两个INTO子句。 因此,PL / pgSQL函数将被定义为:

 CREATE OR REPLACE FUNCTION new_client(lastn character varying, firstn character varying) RETURNS integer AS $BODY$ DECLARE v_id integer; BEGIN -- Inserts the new person record and retrieves the last inserted id INSERT INTO person(lastname, firstname) VALUES (lastn, firstn) RETURNING id INTO v_id; -- Inserts the new client and references the inserted person INSERT INTO client(id) VALUES (v_id); -- Return the new id so we can use it in a select clause or return the new id into the user application RETURN v_id; END; $BODY$ LANGUAGE plpgsql VOLATILE; 

现在我们可以使用以下方式插入新数据:

 SELECT new_client('Smith', 'John'); 

要么

 SELECT * FROM new_client('Smith', 'John'); 

我们得到新创build的ID。

 new_client integer ---------- 1 

看下面的例子

 CREATE TABLE users ( -- make the "id" column a primary key; this also creates -- a UNIQUE constraint and a b+-tree index on the column id SERIAL PRIMARY KEY, name TEXT, age INT4 ); INSERT INTO users (name, age) VALUES ('Mozart', 20); 

然后获取最后插入的ID使用这个表“用户”序列名称“ID”

 SELECT currval(pg_get_serial_sequence('users', 'id')); 
 SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name')) 

你当然需要提供表名和列名。

这将是当前会议/连接http://www.postgresql.org/docs/8.3/static/functions-sequence.html

对于需要获取全部数据logging的人员,可以添加

 returning * 

到查询的最后,获取包含id的所有对象。

尝试这个:

 select nextval('my_seq_name'); // Returns next value 

如果返回1(或者序列的start_value),则将序列重置为原始值,传递false标志:

 select setval('my_seq_name', 1, false); 

除此以外,

 select setval('my_seq_name', nextValue - 1, true); 

这会将序列值恢复到原始状态,“setval”将返回您正在查找的序列值。

如果你只需要检索最后插入的id而不插入任何东西,你可以使用下面的例子

 SELECT id FROM users ORDER BY id DESC LIMIT 1; 

希望可以帮助。