Angenommen, man möchte die ID einer Entity von
1 2 |
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "foo_bar_sequence") |
auf
1 2 |
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) |
migrieren, und dazu explizit eine Sequence in der Datenbank anlegen. Ein Migrationsskript könnte dann so aussehen:
1 2 3 |
CREATE SEQUENCE foo_bar_id_sequence OWNED BY foo_bar.id; ALTER TABLE foo_bar ALTER COLUMN id SET DEFAULT nextval('foo_bar_id_sequence'); SELECT setval('foo_bar_id_sequence', (SELECT max(id) FROM foo_bar)); |
Aaaber: IDs können negativ sein:
org.postgresql.util.PSQLException: ERROR: setval: value -91 is out of bounds for sequence “foo_bar_id_sequence” (1..9223372036854775807)
😄
Naheligende Lösung wäre, das SELECT in
1 |
SELECT setval('foo_bar_id_sequence', (SELECT greatest(max(id), 1) FROM foo_bar)); |
zu ändern. setval
geht allerdings per default aber beim nächsten Wert los, im Fall “1” (wenn gar keine oder nur negative IDs vorhanden sind) also bei 2. Das ist nicht direkt schlimm, aber uncool. Eine (umständliche!) Lösung ist eine Fallunterscheidung – und falls man die Migration viele viele male durchführen muss, verpackt man die Fallunterscheidung in einer FUNCTION:
1 2 3 4 5 6 7 8 9 10 11 12 |
CREATE OR REPLACE FUNCTION safeSetval(_tbl REGCLASS) RETURNS VOID AS $func$ DECLARE maxId INT; BEGIN EXECUTE FORMAT('SELECT max(id) FROM %s;', _tbl) INTO maxId; CASE WHEN maxId ISNULL OR maxId < 0 THEN PERFORM setval(FORMAT('%s_id_sequence', _tbl), 1, FALSE); ELSE PERFORM setval(FORMAT('%s_id_sequence', _tbl), maxId); END CASE; END $func$ LANGUAGE plpgsql; |
Aufruf dann per:
1 |
SELECT safeSetval('foo_bar'); |
Deutlich einfacher ist allerdings:
1 2 |
SELECT setval('foo_bar_id_sequence', (SELECT greatest(max(id) + 1, 1) FROM foo_bar), FALSE); |
FALSE sorgt dafür, dass nicht der nächste Wert genommen wird, sondern genau dieser – und “+ 1” vermeidet einen Wert von 0, der ebenfalls out of bounds wäre.
Danke an Nils für’s vereinfachen! 🙂 Die umständliche Version bleibt trotzdem online als Template für PG Functions.