使用默认值添加不可为空的列时的 Oracle 错误

Posted

技术标签:

【中文标题】使用默认值添加不可为空的列时的 Oracle 错误【英文标题】:Oracle bug when adding not nullable columns with default 【发布时间】:2017-02-15 22:18:56 【问题描述】:

我过去在 Oracle 11g 的各种实例中都遇到过这个错误。无法亲自访问 Oracle 支持以了解这是否是已识别/已解决的问题。

该错误导致查询始终返回列的默认值,即使记录实际上具有不同的值。

它仅在特定查询中出现,它是由使用单个添加语句在先前存在的表中添加具有默认值的不可为空列引起的。

请参阅下面的完整复制品。

DROP TABLE testBugMain;
DROP TABLE testBugAdditional;

-- Create two tables related to one another through real or apparent FK.
CREATE TABLE testBugMain (
    mainid NUMBER(1) NOT NULL,
    str VARCHAR(200) NULL,
    CONSTRAINT PK_testBugMain PRIMARY KEY (mainid)
);
CREATE TABLE testBugAdditional (
    additionalid NUMBER(1) NOT NULL,
    mainid NUMBER(1) NOT NULL,
    CONSTRAINT PK_testBugAdditional PRIMARY KEY (additionalid)
);

-- Insert a couple of values on both.
INSERT INTO testBugMain (mainid, str) VALUES (1, 'test-with-1');
INSERT INTO testBugMain (mainid, str) VALUES (2, 'test-with-2');
INSERT INTO testBugMain (mainid, str) VALUES (3, 'test-with-3');

INSERT INTO testBugAdditional (additionalid, mainid) VALUES (1, 1);
INSERT INTO testBugAdditional (additionalid, mainid) VALUES (2, 2);
INSERT INTO testBugAdditional (additionalid, mainid) VALUES (3, 3);

-- Required for bug to manifest: add a new column, NOT NULL, with DEFAULT value (5 in this case).
-- It needs to be added through an ALTER and both DEFAULT and NOT NULL in the same sentence for the bug to manifest.
ALTER TABLE testBugAdditional ADD bug NUMBER(1) DEFAULT 5 NOT NULL;

-- Update the value on the column, so the query below should return these values instead of 5's.
UPDATE testBugAdditional SET bug = 1 WHERE mainid = 1;
UPDATE testBugAdditional SET bug = 2 WHERE mainid = 2;
UPDATE testBugAdditional SET bug = 3 WHERE mainid = 3;

-- Sanity check (returned values are correct).
SELECT ma.mainid, ma.str, ad.bug FROM testBugMain ma INNER JOIN testBugAdditional ad ON ma.mainid = ad.mainid;

-- Insanity check (returned values are default values).
SELECT mainid, str, bug FROM
(
   SELECT ma.mainid, ma.str, ad.bug FROM testBugMain ma
   LEFT JOIN -- Required for bug to manifest (left join).
   testBugAdditional ad ON ma.mainid = ad.mainid
   ORDER BY ma.mainid ASC -- Required for bug to manifest (any order by, perhaps?).
)
WHERE rownum < 6 -- Required for bug to manifest (pagination);​

虽然暴露 bug 的查询看起来有些复杂,但我认为使用左连接进行排序、分页查询实际上并没有那么奇怪(而且,考虑到所有因素,很少有 bug 清单可能会更糟)。

问题

这是 Oracle 发现/解决的问题吗?

是否有解决此问题的方法?

【问题讨论】:

有问题吗? 你有错误号吗?如果是这样,我可以找到该修复程序是否已被反向移植。 好点,我假设这些问题是隐含的,但现在已将它们直接添加到细节中。其中一部分(解决方法)我自己回答以获取知识。 【参考方案1】:

解决方案/解决方法

要解决此问题,请始终以类似于以下方式将不可为空的列添加到现有表:

-- Add the column as nullable with a default.
ALTER TABLE existingTable ADD newColumn NUMBER(1) DEFAULT 5;
-- Add the not-null constraint.
ALTER TABLE existingTable MODIFY newColumn NOT NULL;

【讨论】:

【参考方案2】:

问题在 12.1 中没有重现这是我的测试用例输出

    MAINID STR                         BUG
---------- -------------------- ----------
         1 test-with-1                   1
         2 test-with-2                   2
         3 test-with-3                   3


    MAINID STR                         BUG
---------- -------------------- ----------
         1 test-with-1                   1
         2 test-with-2                   2
         3 test-with-3                   3

顺便说一句,感谢您整理了一个出色的测试用例。这是如何发布的一个很好的例子。

【讨论】:

以上是关于使用默认值添加不可为空的列时的 Oracle 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何确保 Linq to Sql 不会覆盖或违反不可为空的 DB 默认值?

VS 2015 数据库项目:新的不可空数据字段的数据

在 PSQL 中为可为空的列添加唯一约束

oracle只显示不为空的列

在 NHibernate 映射中为未使用的列提供默认默认值

声明为不可为空的 Kotlin 属性即使具有初始化值也可以为空