PostgreSQLでは、最後のIDをテーブルに挿入するにはどうすればいいですか?
MS SQLにはSCOPE_IDENTITY()があります。
このようなものを使うように私に忠告しないでください。
select max(id) from table
(tl;dr
:オプション3に進む:RETURNINGを使ってINSERT)
Postgresqlにはテーブルのための "id"の概念はなく、単にsequence(代理の主キーのためのデフォルト値として使われますが、必ずしもそうとは限りません、 _ 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でのsequenceの振る舞いは、異なるセッションが干渉しないように設計されているので、競合状態の危険性はありません(別のセッションが私の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
に頼らなければなりません(もちろん、これは他のトランザクションからのコミットされていない挿入を読み込みません)。
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's answer かなり完成しました。最後の挿入値をPL/pgSQL関数内から取得する必要があるという特別な場合だけを追加します。ここでは、オプション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のオプション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
すべてのデータレコードを取得する必要がある人のために、あなたは追加することができます。
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"は探しているシーケンス値を返します。
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)