TL; DR
Hier ist eine Version, in der Sie keinen Menschen benötigen, um einen Wert zu lesen und selbst einzugeben.
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');
Eine andere Möglichkeit wäre, das Functionam Ende dieser Antwort freigegebene wiederverwendbare zu verwenden .
Eine nicht interaktive Lösung
Fügen Sie einfach die beiden anderen Antworten hinzu, für diejenigen von uns, die diese Sequencevon einem nicht interaktiven Skript erstellen lassen müssen, während sie beispielsweise eine Live-Datenbank patchen.
Das heißt, wenn Sie SELECTden Wert nicht manuell eingeben und selbst in eine nachfolgende CREATEAnweisung eingeben möchten.
Kurz gesagt, Sie können nicht tun:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
... da die START [WITH]Klausel in CREATE SEQUENCEeinen Wert erwartet , keine Unterabfrage.
Hinweis: Als Faustregel gilt , dass für alle nicht-CRUD gilt ( dh : als alles andere INSERT, SELECT, UPDATE, DELETE) Aussagen in pgSQL AFAIK.
Tut es setval()jedoch! Somit ist folgendes absolut in Ordnung:
SELECT setval('foo_a_seq', max(a)) FROM foo;
Wenn keine Daten vorhanden sind und Sie nichts darüber wissen (möchten), coalesce()legen Sie den Standardwert fest:
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
-- ^ ^ ^
-- defaults to: 0
Das Einstellen des aktuellen Sequenzwerts 0ist jedoch umständlich, wenn nicht sogar unzulässig.
Die Verwendung der Drei-Parameter-Form von setvalwäre angemessener:
-- vvv
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
-- ^ ^
-- is_called
Durch Einstellen des optionalen dritten Parameters von setvalto falsewird verhindert, dass der nächste nextvaldie Sequenz vor dem Zurückgeben eines Werts vorverlegt, und somit:
Der nächste nextvalgibt genau den angegebenen Wert zurück, und die Sequenzverbesserung beginnt mit dem folgenden nextval.
- Aus diesem Eintrag in der Dokumentation
In einem nicht verwandten Hinweis können Sie auch die Spalte angeben, die die Sequencedirekt mit CREATEbesitzt. Sie müssen sie später nicht mehr ändern:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
Zusammenfassend:
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');
Verwendung einer Function
Wenn Sie dies für mehrere Spalten planen, können Sie alternativ eine tatsächliche verwenden 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;
Verwenden Sie es so:
INSERT INTO foo (data) VALUES ('asdf');
-- ERROR: null value in column "a" violates not-null constraint
SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
-- OK: 1 row(s) affected
SERIALPseudotyp ist jetzt ein Legacy -Typ , der durch die neueGENERATED … AS IDENTITYFunktion ersetzt wird, die in SQL: 2003 , in Postgres 10 und höher definiert ist. Siehe Erklärung .