Неверный набор столбцов

Рассмотрим следующую таблицу с примерно 10M строками

CREATE TABLE user
(
  id bigint NOT NULL,
  ...
  CONSTRAINT user_pk PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
)

Затем я применил следующий alter

ALTER TABLE USER ADD COLUMN BUSINESS_ID    VARCHAR2(50);
--OK
UPDATE USER SET BUSINESS_ID = ID; //~1500 sec
--OK
ALTER TABLE USER ALTER COLUMN BUSINESS_ID SET NOT NULL;

    ERROR: column "business_id" contains null values
    SQL state: 23502

Это очень странно, поскольку столбец id (который был скопирован в столбец business_id) не может содержать нулевые значения, поскольку он является первичным ключом, но, конечно, я проверяю его

select count(*) from USER where BUSINESS_ID is null
    --0 records

Я подозреваю, что это ошибка, просто интересно, не хватает ли я чего-то тривиального

Ответ 1

Единственным логическим объяснением будет параллельный INSERT.
(Использование tbl вместо зарезервированного слова user в качестве имени таблицы.)

ALTER TABLE tbl ADD COLUMN BUSINESS_ID    VARCHAR2(50);
--OK
UPDATE tbl SET BUSINESS_ID = ID; //~1500 sec
--OK

 HERE

ALTER TABLE tbl ALTER COLUMN BUSINESS_ID SET NOT NULL;

Чтобы предотвратить это, используйте вместо этого:

ALTER TABLE tbl
ADD COLUMN BUSINESS_ID VARCHAR(50) DEFAULT ''; -- or whatever is appropriate
...

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

Или запустите все как блок транзакций и убедитесь в исключительной блокировке:

BEGIN;
LOCK tbl;
ALTER ...
UPDATE ...
ALTER ...
COMMIT;

Ответ 2

Может быть, он хочет значение по умолчанию? Postgresql docs в ALTER:

Чтобы добавить столбец, используйте следующую команду:

ALTER TABLE products ADD COLUMN description text;

Новый столбец изначально заполняется любым значением по умолчанию (null, если вы не указываете предложение DEFAULT).

Итак,

ALTER TABLE USER ALTER COLUMN BUSINESS_ID SET DEFAULT="", 
                 ALTER COLUMN BUSINESS_ID SET NOT NULL;

Ответ 3

Вы не можете сделать это при той же транзакции. Добавьте свой столбец и обновите его. Затем в отдельной транзакции задается непустое ограничение.