Как добавить автоинкрементный первичный ключ в существующую таблицу в PostgreSQL?


190

У меня есть таблица с существующими данными. Есть ли способ добавить первичный ключ без удаления и повторного создания таблицы?

Ответы:


355

( Обновлено - спасибо людям, которые прокомментировали )

Современные версии PostgreSQL

Предположим, у вас есть таблица с именем test1, к которой вы хотите добавить автоинкрементный idстолбец первичного ключа (суррогатного). Следующей команды должно быть достаточно в последних версиях PostgreSQL:

   ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;

Старые версии PostgreSQL

В старых версиях PostgreSQL (до 8.x?) Вам приходилось выполнять всю грязную работу. Следующая последовательность команд должна сделать свое дело:

  ALTER TABLE test1 ADD COLUMN id INTEGER;
  CREATE SEQUENCE test_id_seq OWNED BY test1.id;
  ALTER TABLE test ALTER COLUMN id SET DEFAULT nextval('test_id_seq');
  UPDATE test1 SET id = nextval('test_id_seq');

Опять же, в последних версиях Postgres это примерно эквивалентно приведенной выше команде.


3
Я использую ORACLE, поэтому поделиться им может быть полезно парням ORACLE. В ORACLE: ALTER TABLE TEST1 ADD ID NUMBER; ОБНОВЛЕНИЕ ТЕСТ1 SET ID = TEST1_SEQ.NEXTVAL; ALTER TABLE TEST1 ADD ПЕРВИЧНЫЙ КЛЮЧ (ID); создать последовательность TEST1_SEQ перед выполнением оператора UPDATE
msbyuva

Обратите внимание, что ADD PRIMARY KEYтакже создает NOT NULLограничение (протестировано в Postgres 9.3), как и ожидалось.
Джаред Бек,

19
В Postgres вы можете использовать только одну командуALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;
resnyanskiy

1
В дополнение к комментарию @ resnyanskiy, это будет работать, даже если в таблице есть данные. Идентификаторы заполнены, и не установлено нулевое ограничение. Весь ответ можно заменить строкой в ​​этом комментарии.
Synesso

1
@EricWang Спасибо, Эрик, ты прав - я считаю, что это не сработало несколько версий (лет) назад, но я не уверен. Превратил ответ в сообщество-вики.
leonbloy

57
ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;

Это все, что вам нужно:

  1. Добавить id столбец
  2. Заполните его последовательностью от 1 до количества (*).
  3. Установите его как первичный ключ / не ноль.

Кредит дан @resnyanskiy, который дал этот ответ в комментарии.


2
Это должно быть помечено как ответ, и ответ должен принадлежать @resnyanskiy
Эрик Ван

Я должен был сначала понизить pkey и затем запустить это. ALTER TABLE <table> DROP CONSTRAINT <pkey_name>;
Джош Робертсон

10

Чтобы использовать столбец идентификации в v10,

ALTER TABLE test 
ADD COLUMN id { int | bigint | smallint}
GENERATED { BY DEFAULT | ALWAYS } AS IDENTITY PRIMARY KEY;

Для объяснения столбцов идентификации см. Https://blog.2ndquadrant.com/postgresql-10-identity-columns/ .

О разнице между GENERATED DEFAULT и GENERATED ВСЕГДА см. Https://www.cybertec-postgresql.com/en/septions-gains-and-pitfalls/ .

Для изменения последовательности см. Https://popsql.io/learn-sql/postgresql/how-to-alter-sequence-in-postgresql/ .


Проблема с этим решением состоит в том, что, если таблица уже содержит строки, вы получаете ошибку:SQL Error [23502]: ERROR: column "id" contains null values
isapir

3
@isapir: в ранних версиях (стр. 10 и 10.1) была ошибка, приводившая к этой ошибке. Это было исправлено с помощью pg 10.2. Подробности здесь: dba.stackexchange.com/q/200143/3684
Эрвин Брандштеттер

Спасибо @ erwin-brandstetter
Исапир

Год спустя я снова нашел этот ответ, ошибка, по-видимому, исправлена, проголосовал;)
isapir

2

Я приземлился здесь, потому что я тоже искал что-то подобное. В моем случае я копировал данные из набора промежуточных таблиц со многими столбцами в одну таблицу, а также назначал идентификаторы строк для целевой таблицы. Вот вариант вышеуказанных подходов, которые я использовал. Я добавил серийный столбец в конце моей целевой таблицы. Таким образом, мне не нужно иметь заполнитель для этого в операторе вставки. Затем простой выбор * в целевой таблице автоматически заполнил этот столбец. Вот два оператора SQL, которые я использовал в PostgreSQL 9.6.4.

ALTER TABLE target ADD COLUMN some_column SERIAL;
INSERT INTO target SELECT * from source;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.