it-swarm.asia

Bagaimana cara menggunakan currval () di PostgreSQL untuk mendapatkan id yang dimasukkan terakhir?

Saya punya meja:

CREATE TABLE names (id serial, name varchar(20))

Saya ingin "id yang dimasukkan terakhir" dari tabel itu, tanpa menggunakan RETURNING id Pada sisipan. Tampaknya ada fungsi CURRVAL() , tapi saya tidak mengerti bagaimana menggunakannya.

Saya sudah mencoba:

SELECT CURRVAL() AS id FROM names_id_seq
SELECT CURRVAL('names_id_seq')
SELECT CURRVAL('names_id_seq'::regclass)

tapi tidak ada yang bekerja. Bagaimana saya bisa menggunakan currval() untuk mendapatkan id yang dimasukkan terakhir?

70
Jonas

Jika Anda membuat kolom sebagai serial PostgreSQL secara otomatis membuat urutan untuk itu.

Nama urutannya dibuat secara otomatis dan selalu tablename_columnname_seq, dalam kasus Anda urutannya adalah nama names_id_seq.

Setelah memasukkan ke dalam tabel, Anda dapat memanggil currval() dengan nama urutan itu:

postgres=> CREATE TABLE names in schema_name (id serial, name varchar(20));
CREATE TABLE
postgres=> insert into names (name) values ('Arthur Dent');
INSERT 0 1
postgres=> select currval('names_id_seq');
 currval
---------
       1
(1 row)
postgres=>

Alih-alih meng-hardcoding nama urutan, Anda juga dapat menggunakan pg_get_serial_sequence() sebagai gantinya:

select currval(pg_get_serial_sequence('names', 'id'));

Dengan begitu Anda tidak perlu bergantung pada strategi penamaan yang digunakan Postgres.

Atau jika Anda tidak ingin menggunakan nama urutan sama sekali, gunakan lastval()

56

Ini langsung dari Stack Overflow

Seperti yang ditunjukkan oleh @a_horse_with_no_name dan @Jack Douglas, currval hanya berfungsi dengan sesi saat ini. Jadi, jika Anda setuju dengan kenyataan bahwa hasilnya mungkin dipengaruhi oleh transaksi yang tidak dikomit dari sesi lain, dan Anda masih menginginkan sesuatu yang akan bekerja lintas sesi, Anda dapat menggunakan ini:

SELECT last_value FROM your_sequence_name;

Gunakan tautan ke SO untuk informasi lebih lanjut.

Dari dokumentasi Postgres , dengan jelas dinyatakan

Adalah kesalahan untuk memanggil lastval jika nextval belum dipanggil di sesi saat ini.

Jadi saya kira benar-benar berbicara untuk menggunakan dengan benar nilai saat ini atau last_value untuk urutan di seluruh sesi, Anda perlu melakukan sesuatu seperti itu?

SELECT setval('serial_id_seq',nextval('serial_id_seq')-1);

Dengan asumsi, tentu saja, bahwa Anda tidak akan memiliki sisipan atau cara lain menggunakan bidang serial di sesi saat ini.

53
Slak

Anda perlu memanggil nextval untuk urutan ini di sesi ini sebelum currval :

create sequence serial;
select nextval('serial');
 nextval
---------
       1
(1 row)

select currval('serial');
 currval
---------
       1
(1 row)

jadi Anda tidak dapat menemukan 'id yang disisipkan terakhir' dari urutan kecuali jika insert dilakukan di sesi yang sama (transaksi mungkin dibatalkan tetapi urutannya tidak)

seperti yang ditunjukkan dalam jawaban a_horse, create table dengan kolom tipe serial akan secara otomatis membuat urutan dan menggunakannya untuk menghasilkan nilai default untuk kolom, sehingga insert biasanya mengakses nextval secara implisit:

create table my_table(id serial);
NOTICE:  CREATE TABLE will create implicit sequence "my_table_id_seq" for 
         serial column "my_table.id"

\d my_table
                          Table "stack.my_table"
 Column |  Type   |                       Modifiers
--------+---------+-------------------------------------------------------
 id     | integer | not null default nextval('my_table_id_seq'::regclass)

insert into my_table default values;
select currval('my_table_id_seq');
 currval
---------
       1
(1 row)

Jadi ada beberapa masalah dengan berbagai metode ini:

Currval hanya mendapatkan nilai terakhir yang dihasilkan di sesi saat ini - yang sangat bagus jika Anda tidak memiliki hal lain yang menghasilkan nilai, tetapi dalam kasus di mana Anda dapat memanggil pemicu dan/atau memiliki urutan yang ditingkatkan lebih dari sekali dalam transaksi saat ini, tidak akan mengembalikan nilai yang benar. Itu bukan masalah bagi 99% orang di luar sana - tapi itu sesuatu yang harus dipertimbangkan.

Cara terbaik untuk mendapatkan pengidentifikasi unik yang ditetapkan setelah operasi memasukkan menggunakan klausa PENGEMBALIAN. Contoh di bawah ini mengasumsikan bahwa kolom yang diikat ke urutan disebut "id":

insert into table A (cola,colb,colc) values ('val1','val2','val3') returning id;

Perhatikan bahwa kegunaan klausa RETURNING melampaui hanya mendapatkan urutan, karena juga akan:

  • Mengembalikan nilai yang digunakan untuk "penyisipan akhir" (setelah, misalnya pemicu SEBELUM mungkin telah mengubah data yang dimasukkan.)
  • Kembalikan nilai yang sedang dihapus:

    hapus dari tabel A di mana id> 100 kembali *

  • Kembalikan baris yang diubah setelah PEMBARUAN:

    perbarui tabel Satu set X = 'y' di mana blah = 'blech' kembali *

  • Gunakan hasil penghapusan untuk pembaruan:

    DENGAN A sebagai (hapus * dari tabel A sebagai id kembali) pembaruan B setel dihapus = true di mana id dalam (pilih id dari A);

3
chander

Anda perlu GRANT penggunaan pada skema, seperti ini:

GRANT USAGE ON SCHEMA schema_name to user;

dan

GRANT ALL PRIVILEGES ON schema_name.sequence_name TO user;
1
AMML

Jika Anda ingin mendapatkan nilai urutan tanpa memanggil nextval(), dan tanpa harus memodifikasi urutan, saya mengumpulkan fungsi PL/pgSQL untuk menanganinya: Temukan nilai semua urutan basis data

1
Christophe

Saya harus menjalankan kueri walaupun menggunakan SQLALchemy karena saya tidak berhasil menggunakan currval.

nextId = db.session.execute("select last_value from <table>_seq").fetchone()[0] + 1

Ini adalah proyek python flask + postgresql.

1
Jalal

Dalam PostgreSQL 11.2 Anda dapat memperlakukan urutan seperti tabel, tampaknya:

Contoh jika Anda memiliki urutan bernama: 'names_id_seq'

select * from names_id_seq;
 last_value | log_cnt | is_called
------------+---------+-----------
          4 |      32 | t
(1 row)

Itu akan memberi Anda id yang dimasukkan terakhir (4 dalam hal ini) yang berarti bahwa nilai saat ini (atau nilai yang harus digunakan untuk id berikutnya) harus 5.

0
scifisamurai