TL; DR
Вот версия, в которой вам не нужен человек, который сам считывает значение и набирает его.
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');
Другой вариант - использовать повторно используемый Functionобщий ресурс в конце этого ответа.
Неинтерактивное решение
Просто добавив к двум другим ответам, для тех из нас, кому нужно, чтобы они были Sequenceсозданы неинтерактивным сценарием , например, при исправлении живой БД.
То есть, когда вы не хотите SELECTвручную вводить значение и вводить его самостоятельно в следующем CREATEоператоре.
Короче говоря, вы можете не делать:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
... поскольку START [WITH]предложение in CREATE SEQUENCEожидает значение , а не подзапрос.
Примечание: Как правило, это относится ко всем без CRUD ( то есть : ничего, кроме INSERT, SELECT, UPDATE, DELETE) отчетности в PGSQL AFAIK.
Однако setval()делает! Таким образом, абсолютно нормально:
SELECT setval('foo_a_seq', max(a)) FROM foo;
Если данных нет и вы не (хотите) знать об этом, используйте coalesce()для установки значения по умолчанию:
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
Однако установка текущего значения последовательности в значение 0неуклюже, если не незаконно.
Используя форму трехпараметрической setvalбы более целесообразно:
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
Установка необязательного третьего параметра setvalto falseпредотвратит nextvalпродвижение следующей последовательности перед возвратом значения, и, таким образом:
следующий nextvalвернет точно указанное значение, и продвижение последовательности начнется со следующего nextval.
- из этой записи в документации
В несвязанной заметке вы также можете указать столбец, которому принадлежит Sequenceнепосредственно CREATE, вам не нужно изменять его позже:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
В итоге:
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');
Используя Function
В качестве альтернативы, если вы планируете сделать это для нескольких столбцов, вы можете выбрать фактический 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;
Используйте это так:
INSERT INTO foo (data) VALUES ('asdf');
SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
SERIALпсевдотип теперь унаследован , заменен новойGENERATED … AS IDENTITYфункцией, определенной в SQL: 2003 , в Postgres 10 и более поздних версиях. См. Объяснение .