在PostgreSQL中,如何将最后一个ID插入表中?
在MS SQL中,有SCOPE_IDENTITY()。
请不要建议我使用以下内容:
select max(id) from table
在PostgreSQL中,如何将最后一个ID插入表中?
在MS SQL中,有SCOPE_IDENTITY()。
请不要建议我使用以下内容:
select max(id) from table
Answers:
(tl;dr
:转到选项3:使用RETURNING插入)
回想一下,在postgresql中,表没有“ id”概念,只是序列(通常但不一定用作替代主键的默认值,带有SERIAL伪类型)。
如果您有兴趣获取新插入的行的ID,可以采用以下几种方法:
选项1 :CURRVAL(<sequence name>);
。
例如:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
序列的名称必须是已知的,它确实是任意的。在此示例中,我们假定表persons
具有id
使用SERIAL
伪类型创建的列。为了避免依赖于此并感觉更干净,可以改用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();
这与前面的相似,只是您不需要指定序列名称:它会查找最新的修改序列(始终在会话中,与上面相同)。
这两个CURRVAL
和LASTVAL
是完全并行的安全。设计PG中序列的行为是为了使不同的会话不会受到干扰,因此不会出现竞争状况的风险(如果另一个会话在我的INSERT和SELECT之间插入了另一行,我仍然会得到正确的值)。
但是,它们确实有一个潜在的潜在问题。如果数据库中有一些TRIGGER(或RULE),它们在插入persons
表时会在其他表中进行一些额外的插入……那么LASTVAL
可能会给我们错误的值。CURRVAL
如果在同persons
一张表中进行了额外的插入操作,则甚至可能会发生问题(这种情况不太常见,但是风险仍然存在)。
方案3: INSERT
与RETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
这是获取ID的最干净,有效和安全的方法。它没有以前的任何风险。
缺点?几乎没有:您可能需要修改调用INSERT语句的方式(在最坏的情况下,也许您的API或DB层不希望INSERT返回值);它不是标准的SQL(谁在乎);自Postgresql 8.2(2006年12月...)起可用
结论:如果可以,请选择选项3。在其他地方,请选择1。
注意:如果您打算全局获取最后插入的ID(不一定要通过会话),则所有这些方法都无用。为此,您必须诉诸SELECT max(id) FROM table
(当然,这不会从其他事务中读取未提交的插入)。
相反,您绝不应该使用SELECT max(id) FROM table
上述3个选项之一来获取由您的INSERT
语句刚生成的ID ,因为(除性能之外)这不是并发安全的:在您INSERT
和SELECT
另一个会话之间可能已插入另一个记录。
SELECT max(id)
不幸的是,一旦您开始删除行,该操作也不会执行。
1,2,3,4,5
和删除行4和5,最后插入的ID仍然是5,但max()
返回3
RETURNING id;
欢迎使用如何将其插入另一个表的示例 !
RETURNING id
在提供给psql
命令行工具的SQL脚本中使用?
请参阅INSERT语句的RETURNING子句。基本上,INSERT会作为查询加倍,并为您提供插入的值。
insert into names (firstname, lastname) values ('john', 'smith') returning id;
,那么它只是输出ID就像如果你跑select id from names where id=$lastid
直接。如果要将return保存到a变量中,则insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
如果包含return的语句是函数中的最后一条语句,则returning
整个函数将返回正被编辑的id 。
您可以在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
伦勃朗的答案很完整。我只添加一种特殊情况,即需要从选项3不完全适合的PL / pgSQL函数中获取最后插入的值。
例如,如果我们有下表:
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
);
如果需要插入客户记录,则必须引用个人记录。但是,假设我们要设计一个PL / pgSQL函数,该函数可将新记录插入客户端,但还要负责插入新的人记录。为此,我们必须使用leonbloy的OPTION 3的微小变化:
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');
然后,我们获得了新创建的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,请将其用于表“ user”的seq列名称“ 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
Postgres具有相同的内置机制,该机制在同一查询中返回id或您希望查询返回的任何内容。这是一个例子。考虑您创建了一个包含2列column1和column2的表,并且希望在每次插入后返回column1。
# create table users_table(id serial not null primary key, name character varying);
CREATE TABLE
#insert into users_table(name) VALUES ('Jon Snow') RETURNING id;
id
----
1
(1 row)
# insert into users_table(name) VALUES ('Arya Stark') RETURNING id;
id
----
2
(1 row)
我在Java和Postgres中遇到了这个问题。我通过更新新的Connector-J版本修复了它。
postgresql-9.2-1002.jdbc4.jar