Di PostgreSQL, bagaimana cara saya mendapatkan id terakhir dimasukkan ke dalam tabel?
Dalam MS SQL ada SCOPE_IDENTITY ().
Tolong jangan menyarankan saya untuk menggunakan sesuatu seperti ini:
select max(id) from table
Di PostgreSQL, bagaimana cara saya mendapatkan id terakhir dimasukkan ke dalam tabel?
Dalam MS SQL ada SCOPE_IDENTITY ().
Tolong jangan menyarankan saya untuk menggunakan sesuatu seperti ini:
select max(id) from table
Jawaban:
( tl;dr
: opsi goto 3: INSERT dengan RETURNING)
Ingatlah bahwa dalam postgresql tidak ada konsep "id" untuk tabel, hanya urutan (yang biasanya tetapi tidak selalu digunakan sebagai nilai default untuk kunci utama pengganti, dengan SERIAL pseudo-type).
Jika Anda tertarik untuk mendapatkan id dari baris yang baru dimasukkan, ada beberapa cara:
Pilihan 1: CURRVAL(<sequence name>);
.
Sebagai contoh:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
Nama urutan harus diketahui, itu benar-benar sewenang-wenang; dalam contoh ini kita mengasumsikan bahwa tabel persons
memiliki id
kolom yang dibuat dengan tipe SERIAL
pseudo. Untuk menghindari mengandalkan ini dan merasa lebih bersih, Anda bisa menggunakan pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Peringatan: currval()
hanya berfungsi setelah INSERT
(yang telah dieksekusi nextval()
), di sesi yang sama .
Pilihan 2: LASTVAL();
Ini mirip dengan yang sebelumnya, hanya saja Anda tidak perlu menentukan nama urutan: mencari urutan modifikasi terbaru (selalu di dalam sesi Anda, peringatan yang sama seperti di atas).
Keduanya CURRVAL
danLASTVAL
aman secara bersamaan. Perilaku urutan dalam PG dirancang sehingga sesi yang berbeda tidak akan mengganggu, sehingga tidak ada risiko kondisi balapan (jika sesi lain menyisipkan baris lain antara INSERT dan SELECT saya, saya masih mendapatkan nilai yang benar).
Namun mereka memiliki masalah potensial yang tidak kentara. Jika database memiliki beberapa TRIGGER (atau ATURAN) yang, pada saat dimasukkan ke dalam persons
tabel, membuat beberapa tambahan di tabel lain ... maka LASTVAL
mungkin akan memberi kita nilai yang salah. Masalahnya bahkan dapat terjadi dengan CURRVAL
, jika penyisipan tambahan dilakukan ke persons
tabel yang sama (ini jauh lebih jarang, tetapi risikonya masih ada).
Opsi 3: INSERT
denganRETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Ini adalah cara yang paling bersih, efisien dan aman untuk mendapatkan id. Itu tidak memiliki risiko seperti sebelumnya.
Kekurangannya? Hampir tidak ada: Anda mungkin perlu memodifikasi cara Anda memanggil pernyataan INSERT Anda (dalam kasus terburuk, mungkin API atau lapisan DB Anda tidak mengharapkan INSERT untuk mengembalikan nilai); itu bukan SQL standar (siapa yang peduli); ini tersedia sejak Postgresql 8.2 (Des 2006 ...)
Kesimpulan: Jika Anda bisa, pilih opsi 3. Di tempat lain, pilih 1.
Catatan: semua metode ini tidak berguna jika Anda bermaksud mendapatkan id yang dimasukkan terakhir secara global (tidak harus oleh sesi Anda). Untuk ini, Anda harus menggunakan SELECT max(id) FROM table
(tentu saja, ini tidak akan membaca sisipan tanpa komitmen dari transaksi lain).
Sebaliknya, Anda tidak boleh menggunakan SELECT max(id) FROM table
salah satu dari 3 opsi di atas, untuk mendapatkan id yang baru saja dihasilkan oleh INSERT
pernyataan Anda , karena (terlepas dari kinerja) ini tidak bersamaan aman: antara Anda INSERT
dan AndaSELECT
sesi lain mungkin telah memasukkan catatan lain.
SELECT max(id)
sayangnya tidak melakukan pekerjaan itu segera setelah Anda mulai menghapus baris.
1,2,3,4,5
dan menghapus baris 4 dan 5, ID yang dimasukkan terakhir masih 5, tetapi max()
mengembalikan 3.
RETURNING id;
untuk memasukkan ini ke tabel lain akan diterima!
RETURNING id
skrip SQL yang diumpankan ke psql
alat baris perintah?
Lihat klausa KEMBALI dari pernyataan INSERT . Pada dasarnya, INSERT berfungsi ganda sebagai kueri dan mengembalikan nilai yang dimasukkan.
insert into names (firstname, lastname) values ('john', 'smith') returning id;
, maka itu hanya output id sama seperti jika Anda berlari select id from names where id=$lastid
langsung. Jika Anda ingin menyimpan pengembalian ke variabel aa , maka insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
Jika pernyataan yang berisi pengembalian adalah pernyataan terakhir dalam suatu fungsi , maka id yang sedang returning
dikembalikan oleh fungsi secara keseluruhan.
Anda dapat menggunakan klausa RETURNING dalam pernyataan INSERT, seperti berikut ini
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
Jawaban Leonbloy cukup lengkap. Saya hanya akan menambahkan kasus khusus di mana orang perlu mendapatkan nilai yang dimasukkan terakhir dari dalam fungsi PL / pgSQL di mana OPSI 3 tidak cocok persis.
Misalnya, jika kita memiliki tabel berikut:
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
);
Jika kita perlu memasukkan catatan klien, kita harus merujuk ke catatan orang. Tetapi katakanlah kita ingin merancang fungsi PL / pgSQL yang menyisipkan catatan baru ke klien tetapi juga menangani memasukkan catatan orang baru. Untuk itu, kita harus menggunakan sedikit variasi dari OPSI leonbloy's 3:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
Perhatikan bahwa ada dua klausa INTO. Oleh karena itu, fungsi PL / pgSQL akan didefinisikan seperti:
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;
Sekarang kita bisa memasukkan data baru menggunakan:
SELECT new_client('Smith', 'John');
atau
SELECT * FROM new_client('Smith', 'John');
Dan kami mendapatkan id yang baru dibuat.
new_client
integer
----------
1
Lihat contoh di bawah ini
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);
Kemudian untuk mendapatkan id yang dimasukkan terakhir gunakan ini untuk tabel "user" seq nama kolom "id"
SELECT currval(pg_get_serial_sequence('users', 'id'));
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
Anda harus memberikan nama tabel dan nama kolom tentu saja.
Ini akan untuk sesi / koneksi saat ini http://www.postgresql.org/docs/8.3/static/functions-afterence.html
Coba ini:
select nextval('my_seq_name'); // Returns next value
Jika ini mengembalikan 1 (atau apa pun yang merupakan nilai start_untuk urutan Anda), maka setel ulang urutan kembali ke nilai asli, dengan melewati panji palsu:
select setval('my_seq_name', 1, false);
Jika tidak,
select setval('my_seq_name', nextValue - 1, true);
Ini akan mengembalikan nilai urutan ke keadaan semula dan "setval" akan kembali dengan nilai urutan yang Anda cari.
Postgres memiliki mekanisme inbuilt untuk hal yang sama, yang dalam kueri yang sama mengembalikan id atau apa pun yang Anda inginkan kueri kembali. ini sebuah contoh. Pertimbangkan Anda memiliki tabel yang dibuat yang memiliki 2 kolom column1 dan column2 dan Anda ingin agar kolom1 dikembalikan setelah setiap sisipan.
# 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)
Saya punya masalah dengan Java dan Postgres. Saya memperbaikinya dengan memperbarui versi Connector-J baru.
postgresql-9.2-1002.jdbc4.jar
https://jdbc.postgresql.org/download.html : Versi 42.2.12