У меня есть небольшая таблица (~ 30 строк) в моей базе данных Postgres 9.0 с полем целочисленного идентификатора (первичный ключ), которая в настоящее время содержит уникальные последовательные целые числа, начинающиеся с 1, но которая не была создана с использованием ключевого слова serial.
Как я могу изменить эту таблицу так, чтобы с этого момента вставки в эту таблицу заставляли это поле вести себя так, как если бы оно было создано с типом «серийный»?
postgresql
Nicolaskruchten
источник
источник
SERIAL
псевдотип теперь унаследован , заменен новойGENERATED … AS IDENTITY
функцией, определенной в SQL: 2003 , в Postgres 10 и более поздних версиях. См. Объяснение .Ответы:
Посмотрите на следующие команды (особенно на закомментированный блок).
DROP TABLE foo; DROP TABLE bar; CREATE TABLE foo (a int, b text); CREATE TABLE bar (a serial, b text); INSERT INTO foo (a, b) SELECT i, 'foo ' || i::text FROM generate_series(1, 5) i; INSERT INTO bar (b) SELECT 'bar ' || i::text FROM generate_series(1, 5) i; -- blocks of commands to turn foo into bar CREATE SEQUENCE foo_a_seq; ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq'); ALTER TABLE foo ALTER COLUMN a SET NOT NULL; ALTER SEQUENCE foo_a_seq OWNED BY foo.a; -- 8.2 or later SELECT MAX(a) FROM foo; SELECT setval('foo_a_seq', 5); -- replace 5 by SELECT MAX result INSERT INTO foo (b) VALUES('teste'); INSERT INTO bar (b) VALUES('teste'); SELECT * FROM foo; SELECT * FROM bar;
источник
ALTER TABLE foo ADD PRIMARY KEY (a)
.ALTER TABLE foo OWNER TO current_user;
первую очередь.MAX(a)+1
Разве вы не должны установить значение setval?SELECT MAX(a)+1 FROM foo; SELECT setval('foo_a_seq', 6);
Вы также можете использовать
START WITH
для запуска последовательности с определенной точки, хотя setval выполняет то же самое, что и в ответе Эйлера, например,SELECT MAX(a) + 1 FROM foo; CREATE SEQUENCE foo_a_seq START WITH 12345; -- replace 12345 with max above ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
источник
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]
предложение inCREATE SEQUENCE
ожидает значение , а не подзапрос.Однако
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
tofalse
предотвратит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
источник
coalesce(max(a), 0))
что не будет работать в большинстве случаев, поскольку идентификаторы обычно начинаются с 1. Более правильный способcoalesce(max(a), 1))
setval
Функция фактически только устанавливает текущее «последний используется значение» для последовательности. Следующее доступное значение (первое, которое будет фактически использовано) будет на одно больше! Использованиеsetval(..., coalesce(max(a), 1))
в пустом столбце установит для него "начало"2
(следующее доступное значение), как показано в документации .currval
ее никогда не должно быть0
, даже если она не будет отражена в фактическом наборе данных. Используя форму трехпараметрическуюsetval
будет более подходящим:setval(..., coalesce(max(a), 0) + 1, false)
. Ответ обновлен соответственно!