TL; DR
Ini adalah versi di mana Anda tidak memerlukan manusia untuk membaca nilai dan mengetiknya sendiri.
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
Pilihan lain adalah menggunakan yang dapat digunakan kembali Functionbersama di akhir jawaban ini.
Solusi non-interaktif
Hanya menambahkan ke dua jawaban lainnya, bagi kita yang membutuhkan ini Sequencedibuat oleh skrip non-interaktif , sambil menambal DB live-ish misalnya.
Artinya, saat Anda tidak menginginkan SELECTnilainya secara manual dan mengetiknya sendiri ke dalam CREATEpernyataan berikutnya .
Singkatnya, Anda tidak dapat melakukan:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
... karena START [WITH]klausa dalam CREATE SEQUENCEmengharapkan nilai , bukan subkueri.
Catatan: Sebagai aturan praktis, yang berlaku untuk semua non-CRUD ( yaitu : apa pun selain INSERT, SELECT, UPDATE, DELETE) pernyataan dalam pgsql AFAIK.
Namun, setval()lakukan! Jadi, berikut ini baik-baik saja:
SELECT setval('foo_a_seq', max(a)) FROM foo;
Jika tidak ada data dan Anda tidak (ingin) mengetahuinya, gunakan coalesce()untuk menyetel nilai default:
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
Namun, menyetel nilai urutan saat ini ke 0adalah kikuk, jika tidak ilegal.
Menggunakan bentuk tiga parameter dari setvalakan lebih tepat:
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
Menyetel parameter opsional ketiga dari setvalmenjadi falseakan mencegah yang berikutnya nextvalmemajukan urutan sebelum mengembalikan nilai, dan dengan demikian:
next nextvalakan mengembalikan nilai yang ditentukan secara tepat, dan peningkatan urutan dimulai dengan yang berikut ini nextval.
- dari entri ini di dokumentasi
Pada catatan yang tidak terkait, Anda juga dapat menentukan kolom yang memiliki Sequencelangsung dengan CREATE, Anda tidak perlu mengubahnya nanti:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
Singkatnya:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
Menggunakan sebuah Function
Alternatifnya, jika Anda berencana melakukan ini untuk beberapa kolom, Anda dapat memilih untuk menggunakan aktual Function.
CREATE OR REPLACE FUNCTION make_into_serial(table_name TEXT, column_name TEXT) RETURNS INTEGER AS $$
DECLARE
start_with INTEGER;
sequence_name TEXT;
BEGIN
sequence_name := table_name || '_' || column_name || '_seq';
EXECUTE 'SELECT coalesce(max(' || column_name || '), 0) + 1 FROM ' || table_name
INTO start_with;
EXECUTE 'CREATE SEQUENCE ' || sequence_name ||
' START WITH ' || start_with ||
' OWNED BY ' || table_name || '.' || column_name;
EXECUTE 'ALTER TABLE ' || table_name || ' ALTER COLUMN ' || column_name ||
' SET DEFAULT nextVal(''' || sequence_name || ''')';
RETURN start_with;
END;
$$ LANGUAGE plpgsql VOLATILE;
Gunakan seperti ini:
INSERT INTO foo (data) VALUES ('asdf');
SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
SERIALpseudo-type sekarang sudah lama , digantikan olehGENERATED … AS IDENTITYfitur baru yang didefinisikan di SQL: 2003 , di Postgres 10 dan yang lebih baru. Lihat penjelasannya .