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 Function
am 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 Sequence
von einem nicht interaktiven Skript erstellen lassen müssen, während sie beispielsweise eine Live-Datenbank patchen.
Das heißt, wenn Sie SELECT
den Wert nicht manuell eingeben und selbst in eine nachfolgende CREATE
Anweisung 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 SEQUENCE
einen 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 0
ist jedoch umständlich, wenn nicht sogar unzulässig.
Die Verwendung der Drei-Parameter-Form von setval
wä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 setval
to false
wird verhindert, dass der nächste nextval
die Sequenz vor dem Zurückgeben eines Werts vorverlegt, und somit:
Der nächste nextval
gibt 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 Sequence
direkt mit CREATE
besitzt. 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
SERIAL
Pseudotyp ist jetzt ein Legacy -Typ , der durch die neueGENERATED … AS IDENTITY
Funktion ersetzt wird, die in SQL: 2003 , in Postgres 10 und höher definiert ist. Siehe Erklärung .