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
s за допомогою неінтерактивного сценарію , одночасно виправляючи, наприклад, базу даних Live-ish.
Тобто, коли ви не хочете 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;
-- ^ ^ ^
-- defaults to: 0
Однак встановлення поточного значення послідовності 0
є незграбним, якщо не протизаконним. Більш доречним було б
використання трипараметричної форми setval
:
-- vvv
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
-- ^ ^
-- is_called
Встановлення необов’язкового третього параметра значення setval
to 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');
Використання a 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
SERIAL
псевдо-тип тепер застарілий , витіснений новоюGENERATED … AS IDENTITY
функцією, визначеною в SQL: 2003 , у Postgres 10 і пізніших версіях. Див. Пояснення .