Are default values supported in Oracle for columns with char semantics?
我试图在表中添加一列,但是DEFAULT子句产生了令人惊讶的效果。在具有现有行的表中,我添加了一个新列,如下所示:
1 | alter table t add c char(1 char) default 'N' not null; |
当我随后向表中添加检查约束时,它失败了:
1 | alter table t add constraint chk check(c in ('N', 'Y')); |
导致
的原因
1 2 | ERROR at line 1: ORA-02293: cannot validate (T.CHK) - check constraint violated. |
其他信息:
谢谢。
我相信您看到的是一个依赖于几个不同事物交互的错误
-
首先,数据库字符集必须是可变宽度的字符集(即
AL32UTF8 ),以便单个字符可能需要最多四个字节的存储空间。 - 其次,必须使用字符长度语义声明该列
-
第三,从11.1开始,Oracle进行了优化,以便在表中添加一个声明为
NOT NULL 且具有DEFAULT 的列,Oracle可以通过更新数据字典而不是实际存储默认值来做到这一点。表的每一行中的值。
当这两种情况都成立时,似乎返回的值的长度为4,并用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | SQL> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production PL/SQL Release 11.2.0.1.0 - Production CORE 11.2.0.1.0 Production TNS for 64-bit Windows: Version 11.2.0.1.0 - Production NLSRTL Version 11.2.0.1.0 - Production SQL> create table foo( col1 number ); Table created. SQL> insert into foo values( 1 ); 1 row created. SQL> commit; Commit complete. SQL> alter table foo add c char(1 char) default 'N' not null; Table altered. SQL> alter table foo add constraint chk_foo check( c in ('Y', 'N') ); alter table foo add constraint chk_foo check( c in ('Y', 'N') ) * ERROR at line 1: ORA-02293: cannot validate (SCOTT.CHK_FOO) - check constraint violated SQL> select c, dump(c) from foo; C DUMP(C) ---- ------------------------------ N Typ=1 Len=4: 78,0,0,0 |
如果您实际上强制将值存储在表中,则会在没有
1 2 3 4 5 6 7 8 9 10 | SQL> insert into foo(col1) values (2); 1 row created. SQL> select c, dump(c) from foo; C DUMP(C) ---- ------------------------------ N Typ=1 Len=4: 78,0,0,0 N Typ=1 Len=1: 78 |
您还可以发出
的行中未实际存储值的行
1 2 3 4 5 6 7 8 9 10 11 12 | SQL> update foo 2 set c = 'N' 3 where c != 'N'; 1 row updated. SQL> select c, dump(c) from foo; C DUMP(C) ---- ------------------------------ N Typ=1 Len=1: 78 N Typ=1 Len=1: 78 |
您已经提到过,导致ORA-02293错误的原因是因为它插入的是\\'N \\'(带有空格),而不是\\'N \\'。因此违反了您的约束。
更有趣的问题是,为什么要增加该空间?好吧,按照定义,CHAR是固定宽度的,而VARCHAR不是固定宽度。 CHAR将始终填充空白以填充为该列分配的整个内存空间。因为您选择的宽度为1 CHAR,并且AL32UTF8是宽度可变的字符集,所以这似乎与CHAR的固定宽度性质冲突。看起来它被填充以填充\\'N \\'未使用的额外字节。或者,至少,我认为这是正在发生的事情。
您已标记oracle11g,但未指定版本。
这适用于Linux x86-64上的11.2.0.2。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | SQL*Plus: Release 11.2.0.2.0 Production on Mon Mar 26 13:13:52 2012 Copyright (c) 1982, 2010, Oracle. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management and OLAP options SQL> create table tt(a number); Table created. SQL> insert into tt values (1); 1 row created. SQL> commit; Commit complete. SQL> alter table tt add c char(1 char) default 'N' not null; Table altered. SQL> alter table tt add constraint chk check(c in('N','Y')); Table altered. SQL> select * from tt; A C ---------- - 1 N SQL> column dump(c) format a30 SQL> select c, length(c),dump(c) from tt; C LENGTH(C) DUMP(C) - ---------- ------------------------------ N 1 Typ=96 Len=1: 78 |
那么......您的版本可能有错误吗?
希望有帮助。