您好,登錄后才能下訂單哦!
‘小X,問個問題啊,我這里想往一個表里插入另一張表的值。都是vachar2()字段,用length()看,原表那些值的長度都在20以下,目標表是varchar2(22),怎么會報錯插入失敗,超出最大值呢?
‘主任,是同一個庫嗎?用什么判斷值的長度呢?’
‘是同一個庫,用的length()’
聽到這里,不知道各位是否明白原因了呢?
關于長度,有兩個函數很容易混淆,lengthb()和length()。
length()表示字符個數。
lengthb()表示字節數。
比如,在varchar2()中,“abc”算3個字符,“艾爾法”也算三個字符。
“abc”有三個字節,但是”艾爾法“就不一定了。
例子如下:
select a.* ,length(a),lengthb(a) from test1 a;
如上所示, 字符數不等于字節數!
在上面的數據庫中,一個英文字符為1個字節,一個中文為3個字節。在客戶取的值中,是有不少中文的,這就是超出最大值的原因了。
拓展1
不同的字符集,中文的字符長度是不一樣的,甚至英文的長度也會不同。
比如以常見的UTF16,UTF8,GBK為例,英文長度分別為4字節,1字節,1字節,而中文長度為4字節,3字節,2字節。需要注意的是,字節數越大,說明存儲同樣的數據,占用的空間越多,造成的浪費也越多。
拓展2
在oracle中,有兩個總是成對出現的字符集,varchar2()和char(),這兩個的區別就是, char()自動補全,定長;varchar2()長度可變。例子如下:
create table table_char(a char(20));
create table table_varchar2(a varchar2(20));
insert into table_char values ('hello');
insert into table_char values ('你好');
insert into table_char values ('你好你好');
insert into table_varchar2 values ('hello');
insert into table_varchar2 values ('你好');
insert into table_varchar2 values ('你好你好');
table_char如下
table_varchr2如下:
可以看到,char的字節長度總是20,即便真實的長度不足,后面會以空格補全。所以,varchar2()一般來說是比char()節約空間的。但是char也有他的優勢,一般來說,char()的效率比vharchar2()的要高,這就是常說的以空間換時間。
除此之外,varchar2()由于長度可變,可能在修改的時候發生行遷移現象,影響數據庫的IO,所以,一般來說,在不修改或者修改特別少的列,且長度比較統一的列,都是建議在業務設計期間設置為char(),比如身份證號碼,銀行卡號等。
小思考
不知道大家發現沒有,在table_char的截圖中,length(a)分別為20,16,12,這是為什么呢?這里就不公布答案了,大家可以小小的思考下~~~
拓展3
實際上就varchar2()而言,本身是可以指定以字符數量或者字節大小來定義的,看如下例子:
默認不變的情況下,是varchar2(X byte),這個byte可以省略。可以看到,指定byte的時候,插入一個中文是失敗的,而指定char的時候,插入一個中文是成功的。說實話,目前挺少看到用指定char的。
create table varchar_byte(a varchar2(1 byte));
create table varchar_char(a varchar2(1 char));
insert into varchar_byte values ('好');
insert into varchar_char values ('好');
對于兩者,最大長度都是4000,即varchar2(4000 char)和varchar2(4000 byte),所以varchar2(4000 char)>=varchar2(4000)。
恰巧以前碰到過,一個客戶在測試環境設置過一個參數NLS_LENGTH_SEMANTICS,如果設置為byte,那么varchar2()默認就是bytes,如果設置為char,那默認就變成了char,客戶在測試環境設置的char,而且設置的特別大,導致同一個程序在測試庫是跑通的,但在生產庫報列最大值不足。這點需要注意。
總結
這樣看下來,其實客戶的問題十分簡單,在學習數據庫的過程中,最重要的是舉一反三,一定要多思多想多試驗,才能在遇到問題的時候不慌不忙。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。