web-dev-qa-db-ja.com

NULL以外の列セットの変更が失敗する

約1,000万行の次の表を検討してください。

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

次に、次の変更を適用しました

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列にコピーされている)は主キーであるためnull値を含むことができないため、これは非常に奇妙ですが、確認するために

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

これはバグだと思います

19
dimcookies

唯一の論理的な説明はconcurrent 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;
18

たぶんデフォルト値が必要ですか? ALTERのPostgresqlドキュメント

列を追加するには、次のようなコマンドを使用します。

ALTER TABLE products ADD COLUMN description text;

新しい列には、デフォルト値が指定されているものが最初に入力されます(DEFAULT節を指定しない場合は(null))。

そう、

ALTER TABLE USER ALTER COLUMN BUSINESS_ID SET DEFAULT="", 
                 ALTER COLUMN BUSINESS_ID SET NOT NULL;
8
Ondra Žižka

同じトランザクションでそれを行うことはできません。列を追加して更新します。次に、別のトランザクションでnot null制約を設定します。

0
K.z