为什么此Oracle DROP COLUMN会更改另一列的默认值?

时间:2015-09-29 15:00:42

标签: sql oracle oracle11g ddl check-constraints

我们在Oracle数据库中的表上有一种奇怪的情况,其中删除列会导致更改另一列的默认值。这是场景。

我的表中有一些示例数据:

select * from SAMPLE_TABLE ;

ID                                       BUSINESS_KEY
---------------------------------------- ---------------
e59bf31c-49a4-4638-bf6e-7d1be60f4dbb                   1
c0dabf78-d9ca-4072-832e-aeb618c7ed14                   2

我添加了 TYPE1 列,其中包含检查约束( TYPE1_VAL1 TYPE1_VAL2 )和默认值 TYPE1_VAL2

alter table SAMPLE_TABLE add TYPE1 varchar(10) default 'TYPE1_VAL2' not null check(TYPE1 in ('TYPE1_VAL1', 'TYPE1_VAL2'));

Table altered.

我看到默认值( TYPE1_VAL2 )已正确填写:

select * from SAMPLE_TABLE ;

ID                                       BUSINESS_KEY    TYPE1
---------------------------------------- --------------- ----------
e59bf31c-49a4-4638-bf6e-7d1be60f4dbb                   1 TYPE1_VAL2
c0dabf78-d9ca-4072-832e-aeb618c7ed14                   2 TYPE1_VAL2

我添加了另一个列TYPE2,其中包含另一个检查约束( TYPE2_VAL1 TYPE2_VAL2 )和默认值 TYPE2_VAL2

alter table SAMPLE_TABLE add TYPE2 varchar(15) default 'TYPE2_VAL2' not null check(TYPE2 in ('TYPE2_VAL1', 'TYPE2_VAL2'));

Table altered.

再次看到默认值( TYPE2_VAL2 )是正确的:

SYSTEM(SYSTEM) @ DB_USER > select * from SAMPLE_TABLE ;

ID                                       BUSINESS_KEY    TYPE1      TYPE2
---------------------------------------- --------------- ---------- ---------------
e59bf31c-49a4-4638-bf6e-7d1be60f4dbb                   1 TYPE1_VAL2  TYPE2_VAL2
c0dabf78-d9ca-4072-832e-aeb618c7ed14                   2 TYPE1_VAL2  TYPE2_VAL2

现在是奇怪的部分。当我删除第一列时,它似乎将删除列中的默认值应用到剩余列:

ALTER TABLE SAMPLE_TABLE DROP COLUMN TYPE1;

Table altered.

select * from SAMPLE_TABLE ;

ID                                       BUSINESS_KEY    TYPE2
---------------------------------------- --------------- ---------------
e59bf31c-49a4-4638-bf6e-7d1be60f4dbb                   1 TYPE1_VAL2
c0dabf78-d9ca-4072-832e-aeb618c7ed14                   2 TYPE1_VAL2

所以在 TYPE2 列包含 TYPE2_VAL2 之前,突然之后它包含 TYPE1_VAL2 。就好像已删除列的检查约束移动到此列。

这发生在我们运行Oracle Database 11g 11.2.0.4.0版的测试环境中 - 在Linux上运行64位。

在我们当地的CentOS / Oracle XE版本上,我们没有这个问题。

任何想法可能导致这种情况以及我们如何防止这种情况发生。这是设计/错误/我们的错误吗?

1 个答案:

答案 0 :(得分:4)

这是一个Oracle错误。

通过向现有表格添加NOT NULL约束和DEFAULT值的列来触发它。

要快速添加列,Oracle 11g会将默认值存储在数据字典中。 Oracle称之为“添加列优化”。

这比将默认值写入每个表行要快。然后,查询引擎应该使用数据字典中的默认值替换表行中的任何NULL。不幸的是,有几个与此相关的错误。您的似乎是以下的实例:

  

17325413具有DEFAULT值和NOT NULL定义的删除列结束   将丢失的列数据击中磁盘导致损坏

您可以检查已添加的列如下:

 select owner, object_name, name 
 from dba_objects, col$
 where bitand(col$.PROPERTY,1073741824)=1073741824
 and object_id=obj#;

在我们的案例中,我们被一个不同的错误所诱惑,该错误返回了SELECT FOR UPDATE的错误结果。

我们设置参数_add_col_optim_enabled=FALSE以关闭此“优化”。或者,您可以升级到稍后解决这些错误的Oracle版本。

升级或设置上述参数不会修复已损坏的现有表。您必须重新创建该表。