字符長度的一些學習

以下測試在rdbms19.0.0.0中測試。

dump,length,lengthb 函數,可以參考官方文檔

dump函數 :https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions055.htm#SQLRF00635
length函數: https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions088.htm#SQLRF00658

-- 查看數據庫的字符集,爲AL32UTF8,創建表插入漢字。

select * from nls_database_parameters where parameter='NLS_CHARACTERSET'    
create table test_char (a char(4 char),b varchar2(4),c char(4));
insert into test_char values ('我','我','');
commit;

BB@test>desc test_char
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 A                                                  CHAR(4 CHAR)
 B                                                  VARCHAR2(4)
 C                                                  CHAR(4)

BB@test>

BB@test>select * from nls_database_parameters where parameter='NLS_CHARACTERSET';

PARAMETER            VALUE
-------------------- ----------
NLS_CHARACTERSET     AL32UTF8

BB@test>

SQL> insert into test_char values ('我','我','');
1 row inserted
SQL> commit;
Commit complete
SQL> select * from test_char;
A                B    C
---------------- ---- ----
我               我  
SQL> 

BB@test>select dump(a) dumpa ,length(a) lena,lengthb(a) lenba,
       dump(b) dumpb ,length(b) lenb,lengthb(b) lenbb,
       dump(c) dumpc
from test_char;  2    3    4

DUMPA                                        LENA LENBA DUMPB                          LENB LENBB DUMPC
-------------------------------------------- ---- ----- ------------------------------ ---- ----- ----------
Typ=96 Len=6: 230,136,145,32,32,32              4     6 Typ=1 Len=3: 230,136,145          1     3 NULL

BB@test>

-- 說明
typ表示當前的expr值的類型,96表示nchar,1表示varchar2[nvchar2] .
可以參考文檔 :https://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements001.htm#SQLRF30020
test_char表中,A字段是CHAR(4 CHAR)。存儲4個字符。B字段是VARCHAR2(4),最多存儲4字節,C字段CHAR(4)存儲4字節。
如果字符集是AL32UTF8,因此,中文是3字節表示一個漢字。(對於漢字,ZHS16GBK編碼,一個漢字需要2個字節,UTF8需要3個字節)
A列CHAR(4 CHAR),存儲了4個字符的定長數據,230,136,145,32,32,32。前三個表示字符'我',後面3個32表示3個空格。一起表示4個字符的存儲,length(a)=4.但因爲中文字符是3字節,因此lengthb(a)=6 .
B列VARCHAR2(4)是變長,存入一箇中文'我',因此實際length(b)=1,lengthb(b)=3,尾部並未存入空格字符。

目前個人理解,A字段是CHAR(4 CHAR),漢字'我'佔用1個字符,其他三個字符用空格替代。而漢字1個字符是3個字節。所以3+3=6 。所以len=6
所以lengthb(a)也是6 。length(a)表示a的字符長度,定義多少就是多少。

-- 再次舉例,比如下面的,A字段是char (10 char),插入'我我',佔用2個char,剩餘8個補充空格,每個漢字3個字節,所以2*3+8=14 。所以Len=14 。

insert into bb.test_char2 values('我我')
BB@test>select dump(a) from bb.test_char2;
DUMP(A)
--------------------------------------------------------------------------------
Typ=96 Len=14: 230,136,145,230,136,145,32,32,32,32,32,32,32,32
BB@test>desc test_char2
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 A                                                  CHAR(10 CHAR)
BB@test>
BB@test>select length(a),lengthb(a) from bb.test_char2;
 LENGTH(A) LENGTHB(A)
---------- ----------
        10         14
BB@test>
SQL> select dump('我') from dual;  -- 設置了正確的NLS_LANG,沒有亂碼,len=3 .
DUMP('我')
-------------------------
Typ=96 Len=3: 230,136,145
SQL> 
BB@test>select dump('我') from dual;    -- 這個dump結果 len=9 ,原因是沒有設置正確的NLS,查詢導致是亂碼
DUMP('???')
-------------------------------------------------
Typ=96 Len=9: 239,191,189,239,191,189,239,191,189
BB@test>
[oracle@redhat762100 ~]$ export NLS_LANG="SIMPLIFIED CHINESE.AL32UTF8"
[oracle@redhat762100 ~]$ sqlplus /nolog
SQL*Plus: Release 19.0.0.0.0 - Production on 星期三 10月 16 10:55:39 2019 Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
@>conn bb/oracle
已連接。
BB@test>select dump('我') from dual;
DUMP('我')
-------------------------
Typ=96 Len=3: 230,136,145
BB@test>

-- 還是使用表test_char2,字段A是char(10 char),可以包含10箇中文字符,比如插入10個'我',插入11個'我'提示錯誤

BB@test>desc test_char2
 名稱                                    是否爲空? 類型
 ----------------------------------------- -------- ----------------------------
 A                                                  CHAR(10 CHAR)
BB@test>
BB@test>insert into bb.test_char2 values('我我我我我我我我我我');
已創建 1 行。
BB@test>
insert into bb.test_char2 values('我我我我我我我我我我我'); 
BB@test>insert into bb.test_char2 values('我我我我我我我我我我我');
insert into bb.test_char2 values('我我我我我我我我我我我')
                                *
第 1 行出現錯誤:
ORA-12899: 列 "BB"."TEST_CHAR2"."A" 的值太大 (實際值: 11, 最大值: 10)
BB@test>

--查看10個'我'的len是30(10*3=30).

BB@test>select dump('我我我我我我我我我我') from dual;

DUMP('我我我我我我我我我我')
--------------------------------------------------------------------------------
Typ=96 Len=30: 230,136,145,230,136,145,230,136,145,230,136,145,230,136,145,230,1
36,145,230,136,145,230,136,145,230,136,145,230,136,145


BB@test>

-- 再次測試,創建表,字段A爲char 4(也就是4bytes),插入一個漢字'我',是沒有問題的,插入2個漢字'我',提示超過長度了(因爲1個漢字3個bytes)。

create table bb.test_char3(A char(4));
insert into bb.test_char3 values('我');
insert into bb.test_char3 values('我我');
BB@test>insert into bb.test_char3 values('我');
已創建 1 行。
BB@test>insert into bb.test_char3 values('我我');
insert into bb.test_char3 values('我我')
                                 *
第 1 行出現錯誤:
ORA-12899: 列 "BB"."TEST_CHAR3"."A" 的值太大 (實際值: 6, 最大值: 4)
BB@test>
-- 修改A的長度爲6 ,就可以插入兩個'我'了
BB@test>alter table bb.test_char3 modify (A char(6));
表已更改。
BB@test>insert into bb.test_char3 values('我我');
已創建 1 行。

END

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章