Неинтерактивное решение
Просто добавление к двум другим ответам, для тех из нас, кому необходимо, чтобы эти Sequence
были созданы с помощью неинтерактивного сценария , при этом, например, при исправлении базы данных live-ish.
То есть, когда вы не хотите SELECT
значение вручную и введите его самостоятельно в последующий оператор CREATE
.
Короче говоря, вы можете не делать:
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo);
... поскольку предложение START [WITH]
в CREATE SEQUENCE
ожидает значение , а не подзапрос.
Примечание. Как правило, это относится ко всем операторам, не относящимся к CRUD (, т.е. : что-либо, кроме INSERT
, SELECT
, UPDATE
, DELETE
) в * 1030. * pgSQL AFAIK.
Однако, setval()
делает! Таким образом, абсолютно нормально следующее:
SELECT setval('foo_a_seq', max(a)) FROM foo;
Если данных нет и вы не хотите их знать, используйте coalesce()
, чтобы установить значение по умолчанию:
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
-- ^ ^ ^
-- defaults to: 0
Однако текущее значение последовательности, установленное на 0
, является неуклюжим, если не недопустимым.
Использование трехпараметрической формы setval
было бы более уместным:
-- vvv
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
-- ^ ^
-- is_called
Установка необязательного третьего параметра от setval
до 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');
-- 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