Как добавить столбец в базу данных Postgresql, который не допускает нулевые значения?


243

Я добавляю новый столбец «NOT NULL» в свою базу данных Postgresql, используя следующий запрос (очищенный для Интернета):

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL;

Каждый раз, когда я запускаю этот запрос, я получаю следующее сообщение об ошибке:

ERROR:  column "mycolumn" contains null values

Я в тупике. Куда я иду не так?

ПРИМЕЧАНИЕ: я в основном использую pgAdmin III (1.8.4), но я получил ту же ошибку при запуске SQL из терминала.

Ответы:


400

Вы должны установить значение по умолчанию.

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL DEFAULT 'foo';

... some work (set real values as you want)...

ALTER TABLE mytable ALTER COLUMN mycolumn DROP DEFAULT;

1
Хорошее решение. По какой-то причине я не смог попасть в онлайн-документацию postgres, чтобы узнать, какой будет синтаксис для этого.
— Шон Брайт

4
@SeanBright, вы можете получить доступ к postgres doc в автономном режиме, выполнив man ALTER_TABLE :)
— allan.simon

@ allan.simon Я никогда раньше не использовал PostgreSQL, и у меня его нигде не установлено.
— Шон Брайт

2
Чтобы уточнить: значение по умолчанию необходимо только для обновления существующих строк, поэтому его можно сразу же удалить. Все существующие строки были обновлены, когда таблица была изменена (что может занять некоторое время, очевидно)
— MSalters

2
Это не будет работать, если вы хотите использовать другой столбец для вычисления начального значения для существующих строк. Ответ j_random_hacker позволяет это сделать, делая его более надежным.
— jpmc26

82

Как заметили другие, вы должны либо создать столбец, который можно обнулять, либо указать значение DEFAULT. Если это недостаточно гибко (например, если вам нужно как-то вычислить новое значение для каждой строки отдельно), вы можете использовать тот факт, что в PostgreSQL все команды DDL могут выполняться внутри транзакции:

BEGIN;
ALTER TABLE mytable ADD COLUMN mycolumn character varying(50);
UPDATE mytable SET mycolumn = timeofday();    -- Just a silly example
ALTER TABLE mytable ALTER COLUMN mycolumn SET NOT NULL;
COMMIT;

7
даже в транзакции NOT NULL применяется немедленно, поэтому сначала необходимо добавить столбец, заполнить значения, а затем добавить NOT NULL - как и в этом ответе. (проверено на postgres 9.6)
— Бени Чернявский-Паскин

48

Поскольку строки уже существуют в таблице, ALTERоператор пытается вставить NULLво вновь созданный столбец для всех существующих строк. Вам нужно будет добавить столбец как разрешающий NULL, затем заполнить столбец требуемыми значениями, а затем установить его на NOT NULLпотом.


7
Пример того, как это сделать, был бы действительно хорош. В противном случае решение Люка кажется более полным и готовым к использованию.
— Виктор Фараздаги

5

Вам нужно либо определить значение по умолчанию, либо сделать то, что говорит Шон, и добавить его без ограничения NULL, пока вы не заполните его в существующих строках.


2

Задание значения по умолчанию также будет работать при условии, что значение по умолчанию является подходящим.


2
Было бы улучшить ответ, чтобы дать измененный синтаксис для создания столбца со значением по умолчанию (для иллюстрации).
— резкое выступление

1

Или создайте новую таблицу как временную с дополнительным столбцом, скопируйте данные в эту новую таблицу, манипулируя ею по мере необходимости, чтобы заполнить необнуляемый новый столбец, а затем поменяйте местами таблицу с помощью двухэтапного изменения имени.

Да, это сложнее, но вам может потребоваться сделать это таким образом, если вы не хотите большого ОБНОВЛЕНИЯ на живом столе.


3
Я не -1 вас, но я думаю, что с этим могут быть тонкие трудности - например, я держу пари, что существующие индексы, триггеры и представления будут продолжать ссылаться на исходную таблицу даже после переименования, так как я думаю, что они хранят Relid таблицы (которая не меняется), а не ее имя.
— j_random_hacker

1
Да, я должен был заявить, что новая таблица должна быть точной копией оригинала, включая добавление индексов и тому подобное. Мой плохой за то, что слишком короток. Причина этого заключается в том, что существуют также тонкие трудности выполнения ALTER на столе, который может быть живым, и иногда вам нужно ставить его.
— alphadogg

Например, используя подход DEFAULT, вы добавите это значение по умолчанию к каждой строке. Не уверен, как Postgres блокирует стол при этом. Или, если порядок столбцов имеет значение, вы не можете просто добавить столбец с помощью команды ALTER.
— alphadogg

Справедливо, ALTER TABLE блокирует таблицу в соответствии с документацией PostgreSQL, однако ваш не транзакционный подход рискует потерять изменения, если таблица действительно жива. Также я бы предположил, что любой код, который зависит от порядка столбцов, не работает (это может быть вне вашего контроля, конечно).
— j_random_hacker

2
Этот подход также особенно проблематичен, если на таблицу ссылаются индексы внешнего ключа, поскольку все они также должны быть созданы заново.
— Арье Лейб Таурог

0

этот запрос будет автоматически обновлять нули

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) DEFAULT 'whatever' NOT NULL;

-6

Это сработало для меня :)

ALTER TABLE your_table_name ADD COLUMN new_column_name int;

2
На NOT NULLваш запрос нет ограничений. Конечно, это работает.
— Сильвен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.