CHAR的长度是固定的而VARCHAR的长度是可以变化的 比如存储字符串“abc"对于CHAR ()表示你存储的字符将占个字节(包括个空字符)在数据库中它是以空格占位的而同样的VARCHAR ()则只占用个字节的长度只是最大值当你存储的字符小于时按实际长度存储
CHAR的效率比VARCHAR的效率稍高看来cscm_number应该设成 char()
目前VARCHAR是VARCHAR的同义词工业标准的VARCHAR类型可以存储空字符串但是Oracle不这样做尽管它保留以后这样做的权利Oracle自己开发了一个数据类型VARCHAR这个类型不是一个标准的VARCHAR它将在数据库中varchar列可以存储空字符串的特性改为存储NULL值假如你想有向后兼容的能力Oracle建议使用VARCHAR而不是VARCHAR
何时该用CHAR何时该用varchar?
CHAR与VARCHAR是一对矛盾的统一体两者是互补的关系 VARCHAR比CHAR节省空间在效率上比CHAR会稍微差一些即要想获得效率就必须牺牲一定的空间这也就是我们在数据库设计上常说的‘以空间换效率’ VARCHAR虽然比CHAR节省空间但是假如一个VARCHAR列经常被修改而且每次被修改的数据的长度不同这会引起‘行迁移’(Row Migration)现象而这造成多余的I/O是数据库设计和调整中要尽力避免的在这种情况下用CHAR代替VARCHAR会更好一些
关于char和varchar的比较
char类型与char型或字符常量的比较在比较时使用补齐空格的方式进行比较
varchar类型与varchar类型char型和字符常量的比较在比较时不补充空格直接比较
create table tt(A CHAR() A VARCHAR()) ;
INSERT INTO TT VALUES(AA) ;
insert into tt values(AA ) ;
COMMIT ;
CHAR型与字符常量的比较字符常量作为char型处理
与A比较返回行也就是在比较时自动将常量A右补齐空格后比较
select * from tt where a=A ;
A A
A A
A A
与A 比较返回行也就是在比较时自动将常量A右补齐空格后比较
select * from tt where a=A ;
A A
A A
A A
VARCHAR与常量的比较字符常量作为varchar型处理
与A比较返回行也就是在比较时对A不做处理直接比较
select * from TT WHERE A=A;
A A
A A
与A 比较返回行也就是在比较时对A不做处理直接比较
select * from TT WHERE A=A ;
A A
A A
当CHAR类型和VARCHAR类型比较时比较时对字段值是不作处理直接比较的
让A和A直接比较此时是直接比较有一条记录的A和A相同
select * from tt where a=a ;
A A
A A
但是当和decode函数配合使用时出现不同的情况
使用A字段
select decode(aAAAAABBBB) FROM TT ;
DECODE(AAAAAABBBB)
BBBB
BBBB
虽然A字段为char()但是比较时并没有将常量A补空格再与字段A做比较而是直接进行比较也就是将两个比较字段按照varchar类型处理的
因此比较时认为字段A不等于常量A出现两条结果为BBB的记录
进一步验证
select decode(aA AAAABBBB) FROM TT ; 此处是两个空格
DECODE(AAAAAABBBB)
BBBB
BBBB
还是返回两条BBB的记录说明比较的不是按照char型的比较规则处理的
使用A字段
select decode(aAAAAABBBB) FROM TT ;
DECODE(AAAAAABBBB)
AAAA
BBBB
此时是正常的VARCHAR类型之间的比较第一条记录的A字段等于A返回AAA第二行记录的A字段为’A 比较时不等返回BBB
当使用case表达式处理A字段时出现了与decode函数不同的处理结果
使用字段A
select case a when A then AAA else BBB end from tt ;
CASEAWHENATHENAAAELSEBBB
AAA
AAA
在使用case语句中使用A字段与常量A比较时两个比较值按照char型的比较规则处理在右补空格之后进行比较因此返回两条记录
进一步验证如下
select case a when A then AAA else BBB end from tt ;
CASEAWHENATHENAAAELSEBBB
AAA
AAA
此时将常量改为A 比较时仍视为char类型之间的比较将字段A补齐空格后与常量比较
使用A字段
select case a when A then AAA else BBB end from tt ;
CASEAWHENATHENAAAELSEBBB
AAA
BBB
此时是正常的VARCHAR类型之间的比较第一条记录的A字段等于A返回AAA第二行记录的A字段为’A 比较时不等返回BBB
总结
在使用decode函数对char字段做比较时需要注意即使比较的两个字段都是char类型但是decode函数是将其转化varchar类型 进行处理不遵循char型的比较规则
对于char数据在集合操作中按照char的实际数据进行比较而不是按照char型数据的比较规则进行的
下面是一个简单例子
create table t(name char()) ;
create table t(name char()) ;
begin
for i in loop
insert into t values(to_char(i)) ;
insert into t values(to_char(i)) ;
end loop ;
commit;
end ;
select name from t minus select name from t ;
NAME
如果按照char型的比较规则则不应该有返回值
select anem from t intersect select name from t ;
NAME
无返回值也说明集合操作时比较没有按照char型的比较规则
===============================评论============================
对于decode和case对于char类型的差别原因是由于case是表达式而decode是函数
函数中输入参数和返回值一般都定义为varchar类型
多谢指点一时没有想到这里看了一下decode函数的定义如你所述在使用decode的函数对char型数据进行类型转换
下面是decode的函数的参数定义
SQL> desc sysstandarddecode
Parameter Type Mode Default?
(RESULT) NUMBER
EXPR NUMBER IN
PAT NUMBER IN
RES NUMBER IN
(RESULT) VARCHAR
EXPR NUMBER IN
PAT NUMBER IN
RES VARCHAR IN
(RESULT) DATE
EXPR NUMBER IN
PAT NUMBER IN
RES DATE IN
(RESULT) NUMBER
EXPR VARCHAR IN
PAT VARCHAR IN
RES NUMBER IN
(RESULT) VARCHAR
EXPR VARCHAR IN
PAT VARCHAR IN
RES VARCHAR IN
(RESULT) DATE
EXPR VARCHAR IN
PAT VARCHAR IN
RES DATE IN
(RESULT) NUMBER
EXPR DATE IN
PAT DATE IN
RES NUMBER IN
(RESULT) VARCHAR
EXPR DATE IN
PAT DATE IN
RES VARCHAR IN
(RESULT) DATE
EXPR DATE IN
PAT DATE IN
RES DATE IN
(RESULT) SYSSTANDARD
EXPR SYSSTANDARD IN
PAT SYSSTANDARD IN
RES SYSSTANDARD IN
(RESULT) SYSSTANDARD
EXPR SYSSTANDARD IN
PAT SYSSTANDARD IN
RES SYSSTANDARD IN