1. CHAR的長度是固定的,而VARCHAR2的長度是可以變化的, 比如,存儲字符串“abc",對於CHAR (20),表示你存儲的字符將占20個字節(包括17個空字符),在數據庫中它是以空格占位的,而同樣的VARCHAR2 (20)則只占用3個字節的長度,20只是最大值,當你存儲的字符小於20時,按實際長度存儲。
2.CHAR的效率比VARCHAR2的效率稍高。看來cscm_number應該設成 char(19)
3.目前VARCHAR是VARCHAR2的同義詞。工業標准的VARCHAR類型可以存儲空字符串,但是Oracle不這樣做,盡管它保留以後這樣做的權利。Oracle自己開發了一個數據類型VARCHAR2,這個類型不是一個標准的VARCHAR,它將在數據庫中varchar列可以存儲空字符串的特性改為存儲NULL值。假如你想有向後兼容的能力,Oracle建議使用VARCHAR2而不是VARCHAR。
何時該用CHAR,何時該用varchar2?
CHAR與VARCHAR2是一對矛盾的統一體,兩者是互補的關系. VARCHAR2比CHAR節省空間,在效率上比CHAR會稍微差一些,即要想獲得效率,就必須犧牲一定的空間,這也就是我們在數據庫設計上常說的‘以空間換效率’。 VARCHAR2雖然比CHAR節省空間,但是假如一個VARCHAR2列經常被修改,而且每次被修改的數據的長度不同,這會引起‘行遷移’(Row Migration)現象,而這造成多余的I/O,是數據庫設計和調整中要盡力避免的,在這種情況下用CHAR代替VARCHAR2會更好一些。
關於char和varchar2的比較
char類型與char型或字符常量的比較,在比較時使用補齊空格的方式進行比較。
varchar2類型與varchar2類型,char型和字符常量的比較,在比較時不補充空格,直接比較。
create table tt(A1 CHAR(2) , A2 VARCHAR2(2)) ;
INSERT INTO TT VALUES('A','A') ;
insert into tt values('A','A ') ;
COMMIT ;
--CHAR型與字符常量的比較,字符常量作為char型處理
--與'A'比較,返回2行,也就是在比較時自動將常量'A'右補齊空格後比較
select * from tt where a1='A' ;
A1 A2
-- --
A A
A A
--與'A '比較,返回2行,也就是在比較時自動將常量'A'右補齊空格後比較
select * from tt where a1='A ' ;
A1 A2
-- --
A A
A A
--VARCHAR2與常量的比較,字符常量作為varchar2型處理
--與'A'比較,返回1行,也就是在比較時對'A'不做處理,直接比較
select * from TT WHERE A2='A';
A1 A2
-- --
A A
--與'A '比較,返回1行,也就是在比較時對'A'不做處理,直接比較
select * from TT WHERE A2='A ';
A1 A2
-- --
A A
--當CHAR類型和VARCHAR2類型比較時,比較時對字段值是不作處理,直接比較的
--讓A1和A2直接比較,此時是直接比較,有一條記錄的A1和A2相同
select * from tt where a1=a2 ;
A1 A2
-- --
A A
但是當和decode函數配合使用時,出現不同的情況
使用A1字段
select decode(a1,'A','AAAA','BBBB') FROM TT ;
DECODE(A1,'A','AAAA','BBBB')
----------------------------
BBBB
BBBB
雖然A1字段為char(2),但是比較時並沒有將常量'A'補空格再與字段A1做比較,而是直接進行比較,也就是將兩個比較字段按照varchar2類型處理的
因此比較時認為字段A1不等於常量'A',出現兩條結果為'BBB'的記錄。
進一步驗證,
select decode(a1,'A ','AAAA','BBBB') FROM TT ; --此處是兩個空格
DECODE(A1,'A','AAAA','BBBB')
----------------------------
BBBB
BBBB
還是返回兩條'BBB'的記錄,說明比較的不是按照char型的比較規則處理的。
使用A2字段
select decode(a2,'A','AAAA','BBBB') FROM TT ;
DECODE(A2,'A','AAAA','BBBB')
----------------------------
AAAA
BBBB
此時是正常的VARCHAR2類型之間的比較,第一條記錄的A2字段等於'A',返回'AAA',第二行記錄的A2字段為’A ',比較時不等,返回'BBB'
當使用case表達式處理A1字段時,出現了與decode函數不同的處理結果
使用字段A1
select case a1 when 'A' then 'AAA' else 'BBB' end from tt ;
CASEA1WHEN'A'THEN'AAA'ELSE'BBB
------------------------------
AAA
AAA
在使用case語句中使用A1字段與常量'A'比較時,兩個比較值按照char型的比較規則處理,在右補空格之後進行比較,因此返回兩條記錄
進一步驗證,如下,
select case a1 when 'A ' then 'AAA' else 'BBB' end from tt ;
CASEA1WHEN'A'THEN'AAA'ELSE'BBB
------------------------------
AAA
AAA
此時將常量改為'A ',比較時仍視為char類型之間的比較,將字段A1補齊空格後與常量比較。
使用A2字段
select case a2 when 'A' then 'AAA' else 'BBB' end from tt ;
CASEA2WHEN'A'THEN'AAA'ELSE'BBB
------------------------------
AAA
BBB
此時是正常的VARCHAR2類型之間的比較,第一條記錄的A2字段等於'A',返回'AAA',第二行記錄的A2字段為’A ',比較時不等,返回'BBB'
總結,
在使用decode函數對char字段做比較時,需要注意即使比較的兩個字段都是char類型,但是decode函數是將其轉化varchar2類型 進行處理,不遵循char型的比較規則
對於char數據,在集合操作中,按照char的實際數據進行比較,而不是按照char型數據的比較規則進行的。
下面是一個簡單例子
create table t1(name char(10)) ;
create table t2(name char(20)) ;
begin
for i in 1..5 loop
insert into t1 values(to_char(i)) ;
insert into t1 values(to_char(i)) ;
end loop ;
commit;
end ;
select name from t1 minus select name from t2 ;
NAME
--------------------
1
2
3
4
5
如果按照char型的比較規則,則不應該有返回值。
select anem from t1 intersect select name from t2 ;
NAME
--------------------
無返回值,也說明集合操作時比較沒有按照char型的比較規則。
===============================評論2============================
對於decode和case對於char類型的差別,原因是由於case是表達式,而decode是函數。
函數中輸入參數和返回值一般都定義為varchar2類型。
多謝指點,一時沒有想到這裡,看了一下decode函數的定義,如你所述,在使用decode的函數對char型數據進行類型轉換。
下面是decode的函數的參數定義。
SQL> desc sys.standard.decode
Parameter Type Mode Default?
--------- ----------------------- ---- --------
(RESULT) NUMBER
EXPR NUMBER IN
PAT NUMBER IN
RES NUMBER IN
(RESULT) VARCHAR2
EXPR NUMBER IN
PAT NUMBER IN
RES VARCHAR2 IN
(RESULT) DATE
EXPR NUMBER IN
PAT NUMBER IN
RES DATE IN
(RESULT) NUMBER
EXPR VARCHAR2 IN
PAT VARCHAR2 IN
RES NUMBER IN
(RESULT) VARCHAR2
EXPR VARCHAR2 IN
PAT VARCHAR2 IN
RES VARCHAR2 IN
(RESULT) DATE
EXPR VARCHAR2 IN
PAT VARCHAR2 IN
RES DATE IN
(RESULT) NUMBER
EXPR DATE IN
PAT DATE IN
RES NUMBER IN
(RESULT) VARCHAR2
EXPR DATE IN
PAT DATE IN
RES VARCHAR2 IN
(RESULT) DATE
EXPR DATE IN
PAT DATE IN
RES DATE IN
(RESULT) SYS.STANDARD.
EXPR SYS.STANDARD. IN
PAT SYS.STANDARD. IN
RES SYS.STANDARD. IN
(RESULT) SYS.STANDARD.
EXPR SYS.STANDARD. IN
PAT SYS.STANDARD. IN
RES SYS.STANDARD. IN