PostgreSQLで、テーブルに挿入された最後のIDを取得するにはどうすればよいですか?
MS SQLにはSCOPE_IDENTITY()があります。
このようなものを使用するように私に助言しないでください:
select max(id) from table
PostgreSQLで、テーブルに挿入された最後のIDを取得するにはどうすればよいですか?
MS SQLにはSCOPE_IDENTITY()があります。
このようなものを使用するように私に助言しないでください:
select max(id) from table
回答:
(tl;dr
:gotoオプション3:RETURNINGを指定した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
が行われる場合、おそらく誤った値が返されます。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
自分で生成されたIDを取得するために、代わりに上記の3つのオプションのいずれかをINSERT
(離れてパフォーマンスから)これは同時安全ではないので、文を:あなたの間INSERT
とあなたのSELECT
別のセッション別のレコードを挿入している場合があります。
SELECT max(id)
残念ながら、行の削除を開始してもすぐにはジョブは実行されません。
1,2,3,4,5
あり、行4と5を削除した場合、最後に挿入されたIDは5のままですが、max()
3を返します
RETURNING id;
これを別のテーブルに挿入する方法のサンプルは 大歓迎です!
RETURNING id
供給されるSQLスクリプト内でどのように使用できpsql
ますか?
INSERTステートメントのRETURNING句を参照してください。基本的に、INSERTはクエリとしても機能し、挿入された値を返します。
insert into names (firstname, lastname) values ('john', 'smith') returning id;
、あなたが走ったかのように、それは単に出力のID select id from names where id=$lastid
を直接。あなたがしたい場合はAA変数に戻り値を保存し、その後、insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
帰国を含む文がある場合は関数内の最後の文は、その後、idがあることreturning
「edは、全体としての関数によって返されます。
次のように、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関数を考案したいとしましょう。そのためには、レオンブロイのオプション3のわずかなバリエーションを使用する必要があります。
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
2つの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またはクエリが返すものを返します。ここに例があります。column1とcolumn2の2つの列を持つテーブルを作成し、挿入ごとに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
https://jdbc.postgresql.org/download.html:バージョン42.2.12