如何獲取插入到表中的最後一個ID?在MS SQL中有SCOPE_IDENTITY()。postgreSQL函數爲最後插入的ID
請,不建議使用這樣的事情:
select max(id) from table
如何獲取插入到表中的最後一個ID?在MS SQL中有SCOPE_IDENTITY()。postgreSQL函數爲最後插入的ID
請,不建議使用這樣的事情:
select max(id) from table
(tl;dr
:GOTO選項3:與返回的INSERT)
回想一下,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
可能會給我們帶來錯誤的值。如果額外的插入是在同一個persons
表中完成的,這個問題甚至可能發生在CURRVAL
(這通常不太常見,但風險仍然存在)。
方案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
(當然,這不會讀取來自其他事務的未提交插入)。
LASTVAL()可能非常邪惡,以防將觸發器/規則插入到其他表中。 – 2012-10-25 15:17:41
'SELECT max(id)'不幸的是,只要開始刪除行,就不會完成這項工作。 – 2012-11-02 16:44:30
@ SimonA.Eugster爲什麼不呢? – leonbloy 2012-11-02 17:11:22
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
您需要提供表名和過程的列名。
這將是當前會話/連接 http://www.postgresql.org/docs/8.3/static/functions-sequence.html
參見下面的例子
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'));
請參閱INSERT聲明的RETURNING子句。基本上,INSERT加倍作爲查詢,並返回插入的值。
您可以使用INSERT語句,返回條款,就像下面
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
試試這個:
select nextval('my_seq_name'); // Returns next value
如果返回1(或任何對你的序列START_VALUE),然後將序列重置回原始值,通過假標誌:
select setval('my_seq_name', 1, false);
否則,
select setval('my_seq_name', nextValue - 1, true);
這會將序列值恢復到原始狀態,「setval」將返回您正在查找的序列值。
如果你只需要檢索沒有插入任何你可以用下面的例子
SELECT id FROM users ORDER BY id DESC LIMIT 1;
希望能幫最後插入的ID。
Op不要求這種類型的解決方案 – ModChowdhury 2016-05-21 15:13:24
Leonbloy's answer非常完整。我只會添加一個特殊情況,其中需要從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
);
如果我們需要插入我們必須提到一個人記錄客戶記錄。但是讓我們假設我們想要設計一個PL/pgSQL函數來插入一條新記錄到客戶端,但也需要插入新的人員記錄。爲了這一點,我們必須使用leonbloy的OPTION 3的微小的變化:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
注意,有兩成的條款。
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;
現在我們可以使用插入新的數據:因此,PL/pgSQL函數想被定義
SELECT new_client('Smith', 'John');
或
SELECT * FROM new_client('Smith', 'John');
而我們得到新創建的ID 。
new_client
integer
----------
1
對於誰需要獲得所有數據記錄的,你可以添加
returning *
到您的查詢的末尾以獲得包括ID的所有對象。
你爲什麼討厭最大功能?我認爲這很簡單。有沒有安全問題? – 2016-11-25 07:41:06
@ jeongmin.cha如果存在其他操作和更多插入操作(併發操作)之間存在問題,則表示max id已更改,除非並且直到明確地取鎖並且不釋放它 – rohanagarwal 2017-07-14 14:00:51