TL; DR
Burada, bir değeri okuyup kendi başına yazmak için bir insana ihtiyacınız olmayan bir sürüm var.
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');
Diğer bir seçenek Function, bu cevabın sonunda paylaşılan yeniden kullanılabilirliği kullanmak olacaktır .
Etkileşimli olmayan bir çözüm
Diğer iki yanıta ekleyerek, bunların etkileşimli olmayanSequence bir komut dosyasıyla oluşturulmasına ihtiyaç duyanlarımız içinÖrnek olarak live-ish DB'ye yama uygularken, bunların .
Yani, SELECTdeğeri manuel olarak istemediğinizde ve sonraki CREATEifadeye kendiniz yazın .
Kısacası, olabilir değil yapın:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
... içindeki START [WITH]cümle bir alt sorgu değil, CREATE SEQUENCEbir değer beklediğinden .
Not: (olmayan tüm CRUD için de geçerlidir Pratik bir kural olarak, yani : dışında bir INSERT, SELECT, UPDATE, DELETEifadelerden) pgSQL afaik.
Ancak setval()öyle! Bu nedenle, aşağıdakiler kesinlikle iyidir:
SELECT setval('foo_a_seq', max(a)) FROM foo;
Veri yoksa ve bunu bilmek istemiyorsanız (istemiyorsanız) coalesce(), varsayılan değeri ayarlamak için kullanın :
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
Bununla birlikte, mevcut sıra değerinin olarak ayarlanması 0, yasadışı değilse sakar.
Üç parametreli biçimini kullanmak setvaldaha uygun olur:
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
İsteğe bağlı üçüncü bir parametre ayarlanması setvaliçin falseaşağıdaki engeller nextvalve böylece bir değer dönmeden önce sekansı ilerlemesini ve:
sonraki nextvaltam olarak belirtilen değeri döndürecektir ve sıra ilerlemesi aşağıdakilerle başlar nextval.
- belgelerdeki bu girişten
İlişkili olmayan bir notta, Sequencedoğrudan ile sahip olduğu sütunu da belirtebilirsiniz, CREATEdaha sonra değiştirmek zorunda kalmazsınız:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
Özetle:
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');
Bir Function
Alternatif olarak, bunu birden çok sütun için yapmayı planlıyorsanız, bir gerçek kullanmayı tercih edebilirsiniz 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;
Bunu şu şekilde kullanın:
INSERT INTO foo (data) VALUES ('asdf');
SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
SERIALsözde tipi artık eski yeni supplanted,GENERATED … AS IDENTITYözelliği tanımlı içinde 2003: SQL , Postgres 10 ve sonrası. Açıklamaya bakın .