Як я можу додати стовпець до бази даних 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 - як це робить ця відповідь. (випробувано на постгресах 9.6)
Бені Чернявський-Паскін

48

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


7
Приклад того, як це зробити, було б дуже приємно. Інакше рішення Люка здається більш повним та готовим до використання.
Віктор Фараздагі

5

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


2

Визначення значення за замовчуванням також може працювати, якщо вважати, що значення за замовчуванням є відповідним.


2
Відповідь буде вдосконалено, щоб надати змінений синтаксис для створення стовпця зі значенням за замовчуванням (для ілюстрації).
hardmath

1

Або створіть нову таблицю як темп із додатковим стовпцем, скопіюйте дані в цю нову таблицю, маніпулюючи нею, як потрібно, щоб заповнити ненульовий новий стовпець, а потім поміняйте таблицю двоступеневою зміною імені.

Так, це складніше, але вам може знадобитися зробити це таким чином, якщо ви не хочете великого ОНОВЛЕННЯ на живому столі.


3
Я вас не -1, але я думаю, що з цим можуть виникнути тонкі труднощі - наприклад, я роблю ставку на те, що існуючі індекси, тригери та погляди продовжуватимуть посилатися на початкову таблицю навіть після перейменування, оскільки я думаю, що вони зберігають відновлення таблиці (яка не змінюється), а не її назва.
j_random_hacker

1
Так, я мав би зазначити, що нова таблиця повинна бути точною копією оригіналу, включаючи додавання індексів та іншого. Моє погано за те, що я занадто короткий. Причиною цього є те, що існують також тонкі труднощі виконання ALTER на столі, який може бути в прямому ефірі, і іноді вам потрібно його скласти.
альфадогг

Наприклад, використовуючи підхід DEFAULT, ви додасте це значення за замовчуванням до кожного рядка. Не впевнений, як Postgres блокує таблицю, роблячи це. Або, якщо порядок стовпців має значення, ви не можете просто додати стовпець за допомогою команди ALTER.
альфадог

Досить справедливо, ALTER TABLE блокує таблицю відповідно до документів PostgreSQL, однак ваш не транзакційний підхід ризикує втратити зміни, якщо таблиця дійсно працює. Також я б запропонував, що будь-який код, який спирається на порядок стовпців, порушений (це може бути поза вашим контролем, звичайно).
j_random_hacker

2
Такий підхід також є особливо проблематичним, якщо таблиця посилається на іноземні ключові індекси, оскільки всі вони також повинні бути відтворені.
Aryeh Leib Taurog

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.