【问题标题】:Alter column set not null failsAlter column set not null 失败
【发布时间】:2013-11-02 01:56:02
【问题描述】:

考虑下表,其中大约有 1000 万行

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 列)不能包含空值,因为它是主键,但要确保我检查它

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

我怀疑这是一个错误,只是想知道我是否遗漏了一些微不足道的东西

【问题讨论】:

  • 我对为什么会发生这种情况一无所知。也许尝试使用显式转换的 UPDATE:UPDATE "user" set business_id = ID::VARCHAR
  • 这可能与“user”是保留字这一事实有关,但我真的不知道。保留字列表:postgresql.org/docs/current/static/sql-keywords-appendix.html
  • Postgres 中没有 VARCHAR2 类型。你的任务有问题..
  • @bma user 不是表的实际名称,我只是简化它来写问题
  • @Erwin Brandstetter 数据库是启用了 oracle 兼容性的 EnterpriseDB

标签: postgresql alter notnull enterprisedb


【解决方案1】:

唯一合乎逻辑的解释是并发INSERT
(使用tbl代替保留字user作为表名。)

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

-- concurrent INSERT HERE !!!

ALTER TABLE tbl ALTER COLUMN BUSINESS_ID SET NOT NULL;</code></pre>

为了防止这种情况,请改用:

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

您最终可能会在某些行中使用默认值。你可能想检查一下。

或将所有内容作为事务块运行:

BEGIN;
-- LOCK tbl; -- not needed
ALTER ...
UPDATE ...
ALTER ...
COMMIT;

您可能会使用排他锁,但ALTER TABLE .. ADD COLUMN 无论如何都会使用ACCESS EXCLUSIVE 锁。 (它只在事务结束时释放,就像所有的锁一样。)

【讨论】:

  • 不幸的是,情况并非如此,没有其他与数据库的连接,也没有应用进一步的插入语句。此外,计数函数返回 0 为 BUSINESS_ID is null
  • 不幸的是,我不能使用默认值,因为这应该是唯一的列(在该语句之后添加了唯一约束)。我尝试了事务块,但这似乎并没有改变什么。这似乎是一个错误,我们将联系 EnterpriseDb 支持,我只是想看看我是否缺少明显的东西。无论如何,感谢您的宝贵时间
  • @Gokul:是的,但 7.3 是古老的。查看您的 Postgres 版本的手册页:postgresql.org/docs/current/static/ddl-alter.html
【解决方案2】:

也许它想要一个默认值? Postgresql docs on ALTER:

要添加列,请使用如下命令:

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;

【讨论】:

  • 如果是整数,我必须将其更改为SET DEFAULT 0
【解决方案3】:

您不能在同一笔交易中这样做。添加您的列并更新它。然后在单独的事务中设置非空约束。

【讨论】:

  • 这不是在同一个事务上运行的,它们是单独的命令
猜你喜欢
  • 2014-04-17
  • 2013-12-26
  • 2017-09-21
  • 1970-01-01
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 2018-08-24
  • 2022-01-19
相关资源
最近更新 更多