TL; DR
Oto wersja, w której nie potrzebujesz człowieka do odczytania wartości i wpisania jej samodzielnie.
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');
Inną opcją byłoby wykorzystanie Function
udostępnionego na końcu tej odpowiedzi pliku wielokrotnego użytku .
Rozwiązanie nieinteraktywne
Po prostu dodając do pozostałych dwóch odpowiedzi, dla tych z nas, którzy potrzebują mieć je Sequence
utworzone za pomocą nieinteraktywnego skryptu , na przykład poprawiając dynamiczną bazę danych.
Oznacza to, że nie chcesz SELECT
ręcznie wpisywać wartości i wpisywać ją samodzielnie w kolejnej CREATE
instrukcji.
W skrócie, można nie zrobić:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
... ponieważ START [WITH]
klauzula in CREATE SEQUENCE
oczekuje wartości , a nie podzapytania.
Uwaga: Jako zasada, która dotyczy wszystkich non-CRUD ( tj : niczego innego niż INSERT
, SELECT
, UPDATE
, DELETE
) sprawozdania w pgSQL AFAIK.
Jednak setval()
tak! Zatem absolutnie w porządku:
SELECT setval('foo_a_seq', max(a)) FROM foo;
Jeśli nie ma danych i nie (chcesz) o tym wiedzieć, użyj, coalesce()
aby ustawić wartość domyślną:
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
Jednak ustawienie bieżącej wartości sekwencji na 0
jest niezdarne, jeśli nie nielegalne. Bardziej odpowiednie byłoby
użycie trzyparametrowej formy setval
:
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
Ustawienie opcjonalnego trzeciego parametru setval
na false
to uniemożliwi następnemu nextval
przesunięcie sekwencji przed zwróceniem wartości, a zatem:
next nextval
zwróci dokładnie określoną wartość, a postęp sekwencji rozpocznie się od następującego nextval
.
- z tego wpisu w dokumentacji
W niepowiązanej notatce możesz również określić kolumnę będącą właścicielem Sequence
bezpośrednio z CREATE
, nie musisz jej później zmieniać:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
W podsumowaniu:
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');
Używać Function
Alternatywnie, jeśli planujesz to zrobić dla wielu kolumn, możesz zdecydować się na użycie rzeczywistego pliku 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;
Użyj go w ten sposób:
INSERT INTO foo (data) VALUES ('asdf');
SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
SERIAL
pseudo-typ jest teraz starszy , wyparty przez nowąGENERATED … AS IDENTITY
funkcję zdefiniowaną w SQL: 2003 , w Postgres 10 i nowszych. Zobacz wyjaśnienie .