Ø 簡介
本文主要來討論 Oracle 中的數據類型,包括以下內容:
1. 概念介紹
2. 數值類型
3. 字符類型
4. 日期類型
5. 大數據與二進制類型
6. 列舉常用類型的數字代碼
1. 概念介紹
在我們的程序中有各種數據類型,而在 Oracle 中也有很多種類型,其實每一種語言的數據類型都會跟數據庫中的數據類型大致的對應起來。比如:
在 Oracle 中主要分為四大數據類型,即:數字類型、字符類型、日期類型,以及大數據與二進制類型,下面就來討論着幾種常用的數據類型。
2. 數值類型
1) NUMBER(Type = 2)
number 類型是 Oracle 中常用的數據類型,即可以用於存儲整數,也可以存儲小數,是一個非常有意思的數據類型。number 是一個可變長度的數據類型,並且始終保持四舍五入的原則。
number 可以指定兩個參數 number(p,s):
l p表示有效位,從左邊第一個非0的數字開始數,到結尾的長度,取值范圍:1 ~ 38;
l s表示小數位,取值范圍:-84 ~ 127。
注意:通常情況下(需要整數位時),應該 p > s,例如:
1. number(3,2) 只能存儲:0.01 ~ 9.99 和 -0.01 ~ -9.99
2. number(3,3) 只能存儲:0.001 ~ 0.999 和 -0.001 ~ -0.999
3. number(2,3) 只能存儲:0.001 ~ 0.099 和 -0.001 ~ -0.099
n number 可以表示的數值范圍:-1.0e-130 ~ 1.0e+126,占用空間為1 ~ 22 個字節。
下面看幾個常見的例子:
1. number
create table t_number(num number);
insert into t_number values(56);
insert into t_number values(56.78);
select * from t_number;
執行以上語句,實際存儲為56和56.78。當不指定有效位和小數位時,number 可根據實際值而確定。
查看占用字節情況:select num, dump(num) from t_number;
56占用2個字節;而56.78占用3個字節
2. number(3)
create table t_number3(num number(3));
insert into t_number3 values(999);
insert into t_number3 values(28.56);
select * from t_number3;
執行以上語句,實際存儲為999和29,表示存儲為整數形式,小數位進行四舍五入。
number(3) 相當於 number(3,0),取值范圍為:-999~999
3. number(5,2)
create table t_number5_2(num number(5,2));
insert into t_number5_2 values(128.264);
insert into t_number5_2 values(128.265);
select * from t_number5_2;
執行以上語句,實際存儲為128.26和128.27,當小數位大於指定范圍時,將進行四舍五入。
n 更多例子
范圍 |
插入值1 |
結果 |
插入值2 |
結果 |
number(5,2) |
23.56 |
23.56 |
0.008 |
0.01 |
number(4,3) |
123.45 |
報錯 |
3.45 |
3.45 |
number(5,5) |
0.2 |
0.2 |
0.000012 |
0.00001 |
number(3,-2) |
182 |
200 |
142.85 |
100 |
number(2,3) |
0.123 |
報錯 |
0.023 |
0.023 |
0.23 |
報錯 |
|
|
|
number(3,3) |
0.234 |
0.234 |
0.23 |
0.23 |
0.1 |
0.1 |
|
|
|
number(6,3) |
999.9995 |
999.999 |
0.0095 |
0.01 |
n 總結
1) 有效位范圍表示,從左邊數第一個非0數值開始,到最后一個數值的長度范圍。例如:number(3,2) 最大值:9.99,最小值:0.01 或 0
2) 是不是發現,number 確實是一個很有意思的數據類型。它通過有效位(P)和小數位(S),就可以精確設置該字段可以存儲的數據范圍。
3) 在平常開發中,對於已知長度數值類型,建議指定有效位和小數位;對於未知長度的數值,可以使用 number。
2) 其他數值類型介紹
類型 |
描述 |
存儲描述 |
DECIMAL(P,S) |
數字類型 |
P為有效位,S為小數 |
INTEGER |
整數類型 |
小的整數 |
FLOAT |
浮點數類型 |
NUMBER(38), 雙精度 |
REAL |
實數類型 |
NUMBER(63), 精度更高 |
create table t_test_number(deci decimal, i integer, f float, r real);
insert into t_test_number values(12.23, 23.55, 22.35, 32.523);
select * from t_test_number;
執行以上語句,將看到如下結果:
說明:這些數據類型應該都屬於 number 類型的“變種”,而且使用 number 類型都能替代這些數據類型,所以這里不過多去研究它們。
3. 字符類型
1) CHAR(Type = 96)
用於存儲固定長度的字符串,一個空間占用1個字節,最多存儲2000個字節,即:char(2000),這里的2000表示字節數。通常也就是1000個漢字,或者2000個字母、數字等。示例:
create table t_char(name char(10));
insert into t_char values('中國');
insert into t_char values('ab12');
commit;
select name, dump(name) from t_char;
執行以上語句將看到如下結果:
由圖可見,兩次插入的字符都不足指定長度,便以空格的字節(32)補齊了,總長度依然是10個字節;另外,當插入數據時超過指定長度將報錯,。
2) NCHAR(Type = 96)
根據字符集而定的固定長度字符串。用於存儲固定長度的字符串,一個空間占用2個字節,最多存儲2000個字節,即:nchar(1000),注意這里的1000表示字符數。
為什么說是字符數呢?N表示是以 unicode 編碼格式存儲,無論中文或英文、數字都以一個字符(2個字節)來存儲,這也是 CHAR 與 NCHAR 最大的區別。看示例:
create table t_nchar(name nchar(10));
insert into t_nchar values('中國');
insert into t_nchar values('ab12');
commit;
select name, dump(name) from t_nchar;
由圖可見,無論是中文或英文都是一個字符占用兩個字節,所以 nchar(10) 可以存儲10中文,同時也只能存儲10英文或數字。例如:
insert into t_nchar values('中華人民共和國中華人');
insert into t_nchar values('abcde12345');
3) VARCHAR2(Type = 1)
VARCHAR2 與 CHAR 類似,不同的是 VARCHAR2 用於存儲可變長度的字符串。最大長度是 CHAR 的兩倍,也就是4000個字節,即:varchar2(4000) ,通常也就是2000個漢字,或者4000個字母、數字等。示例:
create table t_varchar2(name varchar2(10));
insert into t_varchar2 values('中國');
insert into t_varchar2 values('ab12');
commit;
select name, dump(name) from t_varchar2;
執行以上語句將看到如下結果:
可以看到與 char 不一樣,兩次插入都沒有滿足10個字節,是多少個字節就存多少個字節,並沒有以空格(byte 32)去補齊,幫我們節省了空間。
4) NVARCHAR2(Type = 4)
根據字符集而定的可變長度字符串。NVARCHAR2 與 NCHAR 類似,不同的是 NVARCHAR2 用於存儲可變長度的字符串。最大長度是 NCHAR 的兩倍,也就是4000個字節,即:nvarchar2(2000) ,通常也就是2000個漢字、字母、數字等。示例:
create table t_nvarchar2(name nvarchar2(10));
insert into t_nvarchar2 values('中國');
insert into t_nvarchar2 values('ab12');
commit;
select name, dump(name) from t_nvarchar2;
執行以上語句將看到如下結果:
由圖可見,與 NCHAR 一樣,一個英文或數字都占用了兩個字節,但是長度是不固定的。
l 使用 NVARCHAR2 類型存儲多國語言,例如:
CREATE TABLE T1(Id int, Name nvarchar2(256));
INSERT INTO T1 VALUES(1, N'ﺪ اﻟﻤﺠﻴﺪ ﻋﺰﻳﺰ اﻟﺰﻧﺪاﻧﻲ');
INSERT INTO T1 VALUES(2, N'中國삼성abc');
SELECT * FROM T1;
DROP TABLE T1;
n 總結
四種字符類型比較:
類型 |
可變長度 |
一個空間占用字節數 |
最大字節數(bytes) |
適用場景 |
CHAR |
否 |
1 |
2000、 char(2000) |
定長:英文、數字 |
NCHAR |
否 |
2 |
2000, nchar(1000) |
定長:中文 |
VARCHAR2 |
是 |
1 |
4000, varchar2(40000) |
變長:英文、數字、中文 |
NCARCHAR2 |
是 |
2 |
4000, ncarchar2(2000) |
變長:中文 |
1. 對於中文,在這四種類型中存儲,都是占2個或2個以上字節;
2. 對於英文或數字,在 CHAR 和 VARCHAR2 中占一個字節,在 NCHAR 和 NVARCHAR2 中占兩個字節。
n VARCHAR2 與 CHAR 的區別:
大家可能為想既然 varchar2 這么有優勢,為什么需要 char 呢,不是多余么?
答案:當然不是,char 也有它自己的有優勢。當我們存儲已知固定長度的數據時,比如:手機號(11位)、身份證號碼(18位)等,可以考慮使用 char。因為,在查詢數據時,對於 char 類型字段,是全字符整體匹配;而 varchar2 是一個字符一個字符的進行匹配。所以,從查詢效率上,char 要比 varchar2 高。nchar 與 nvarchar2 同樣如此。
n VARCHAR 與 VARCHAR2 的區別
首先,Oracle 一直不鼓勵使用 VARCHAR 類型,盡管 VARCHAR 數據類型當前與 VARCHAR2 是同義的,但是建議使用 VARCHAR2 類型。
經過測試,並沒有發現有什么區別:
create table t_varchar(id number, name varchar(4000));
insert into t_varchar values('中國');
insert into t_varchar values('ab12');
commit;
select name, dump(name) from t_varchar;
1) 都是存儲可變長度的字符串;
2) 存儲最大長度沒區別;
3) 就連存儲類型都與 varchar2 一致:
4) 對空字符串和 null 的處理(比如判斷條件)
5) 當存儲多國語言時,需要采用 NVARCHAR2,而 VARCHAR2 不能。
n 注意事項:
1) 在 ORACLE 數據庫漢字占用幾個字節,是根據 ORACLE 中字符集編碼決定,一般情況,數據庫的 NLS_CHARACTERSET 為 AL32UTF8 或 UTF8,一個漢字占三到四個字節;如果 NLS_CHARACTERSET 為 ZHS16GBK,則一個字符占兩個字節。
2) 通常在創建表時,對於字符串類型(char、varchar2等),建議指定長度為16的倍數,例如:char(16)、char(32)、char(64)、char(128)等,這樣便是有規律的,從可讀性上有利於閱讀和記憶,當然這並不是強制性的。
3) 當我們創建表時,對於存儲已知固定長度的字符串,建議使用 char/nchar 類型;而未知長度的字符串,建議使用 varchar2/nvarchar2 類型。
4. 日期類型
Oracle 日期類型主要使用 DATE 和 TIMESTAMP 數據類型。
1) DATE
date 用於存儲日期和時間類型,date 類型的默認格式為:DD-MM-YYYY,當我插入熟悉的 YYYY-MM-DD 格式時,需要進行格式轉換。示例:
create table t_date(birth date);
下面是插入數據的幾種方式:
插入語句 |
結果 |
insert into t_date values('22-12月-2018'); |
2018/12/22 |
insert into t_date values(to_date('2018-12-22', 'yyyy-mm-dd')); |
2018/12/22 |
insert into t_date values(to_date('2018-12-22 15:22:16', 'yyyy-mm-dd hh24:mi:ss')); |
2018/12/22 15:22:16 |
insert into t_date values('2018-12-22'); |
ORA-01861: 文字與格式字符串不匹配 |
insert into t_date values('22-12-18'); |
ORA-01843: 無效的月份 |
insert into t_date values('22-12-2018'); |
ORA-01843: 無效的月份 |
insert into t_date values('12月-22-2018'); |
ORA-01861: 文字與格式字符串不匹配 |
insert into t_date values('22-12月-2018 10:17:25'); |
ORA-01830: 日期格式圖片在轉換整個輸入字符串之前結束 |
insert into t_date values(to_date('2018-12-22 15:22:16', 'yyyy-mm-dd hh:mi:ss')); |
ORA-01849: 小時值必須介於 1 和 12 之間 |
2) TIMESTAMP
時間戳類型,與 DATE 相比較,TIMESTAMP 類型具有小數位毫秒數,比 DATE 的精度更高。示例:
create table t_timestamp(times timestamp);
下面是插入數據的幾種方式:
插入語句 |
結果 |
insert into t_timestamp values('22-12月-2018'); |
22-12月-18 12.00.00.000000 上午 |
insert into t_timestamp values(to_date('2018-12-22', 'yyyy-mm-dd')); |
22-12月-18 12.00.00.000000 上午 |
insert into t_timestamp values(to_date('2018-12-22 15:22:26', 'yyyy-mm-dd hh24:mi:ss')); |
22-12月-18 03.22.26.000000 下午 |
insert into t_timestamp values(to_timestamp('2018-12-22 15:22:26.256', 'yyyy-mm-dd hh24:mi:ss.ff')); |
22-12月-18 03.22.26.256000 下午 #注意:未指定毫秒數長度時,根據具體值的毫秒數進行轉換(比如6位就轉為6位)。 |
insert into t_timestamp values(to_timestamp('2018-12-22 15:22:26.2567', 'yyyy-mm-dd hh24:mi:ss.ff4')); |
22-12月-18 03.22.26.256700 下午 #指定毫秒數 |
5. 大數據類型與二進制類型
從前面的字符類型了解到,varchar2 最大可以存儲2000個中文或4000個英文;而 nvarchar2 只能存2000個中文或英文,當着兩個數據類型不夠存儲時,我們可以考慮使用大數據 long、clob 等類型來存儲。
1) LONG
用於存儲可變長度的超長字符串,最大長度為2G,通常用於存儲備注字段,或者 varchar2 和 nvarchar2 不夠存儲時。示例:
create table t_long(name long);
insert into t_long values('李a1');
提示:LONG 是一種較老的數據類型,將來會逐漸被BLOB、CLOB、NCLOB等大的對象數據類型所取代。
2) CLOB
CLOB 是一種字符型大型對象(Character Large Object),最大長度為4G,存儲與字符集相關。示例:
create table t_clob(name clob);
insert into t_clob values('李a2');
3) NCLOB
根據字符集而定的字符數據,最大長度為4G。示例:
create table t_nclob(name nclob);
insert into t_nclob values('李a3');
4) BLOB
BLOG 是一種二進制大型對象(Binary Large Object),最大長度為4G,適用於存儲非文本的字節流數據,如:視頻、音頻等。示例:
create table t_blob(name blob);
提示:由於視頻、音頻文件存儲在數據庫中會進行轉碼(壓碼、解碼),所以通常並不會將這些數據存儲在數據庫中。但是存儲在數據庫中會比較安全,也支持該方式去存儲。
5) RAW
固定長度的二進制數據,最大長度 2000個字節,可存儲多媒體視頻、音頻格式等。
6) LONG RAW
可變長度的二進制數據,最大長度2G,與 RAW 類似。
7) BFILE
存儲在數據庫之外的二進制數據,最大長度4G。
8) ROWID
行地址,十六進制串,表示行在所在的表中唯一的行地址,該數據類型主要用於返回ROWID偽列,常用在可以將表中的每一條記錄都加以唯一標識的場合。數據表中記錄的唯一行號,占10個字節。例如:
SELECT t1.rowid, dump(t1.rowid) bytes, t1.empno, t1.ename FROM emp t1;
9) NROWID
二進制數據表中記錄的唯一行號,最大長度4000個字節。
6. 列舉常用類型的數字代碼
CREATE TABLE Temp01(ID number, Data_Type varchar2(16), Value varchar2(256), Type varchar2(256));
declare
v_integer integer := 22;
v_decimal decimal(5,2) := 22.6;
v_float float := 22.7;
v_real real := 22.8;
v_number number(5,2) := 22.9;
v_char char(1) := 'z';
v_nchar nchar(1) := '中';
v_varchar2 varchar2(2) := 'z';
v_nvarchar2 nvarchar2(2) := '中';
v_varchar varchar(1) := 'z';
v_date date := to_date('2020-12-31', 'yyyy-mm-dd');
v_timestamp timestamp := to_timestamp('2020-12-31 23:59:59.999', 'yyyy-mm-dd hh24:mi:ss.ff3');
v_long long := 'aaa';
begin
INSERT INTO Temp01 SELECT * FROM (
SELECT 1, 'integer', to_char(v_integer), dump(v_integer) FROM dual UNION
SELECT 2, 'decimal(5,2)', to_char(v_decimal), dump(v_decimal) FROM dual UNION
SELECT 3, 'float', to_char(v_float), dump(v_float) FROM dual UNION
SELECT 4, 'real', to_char(v_real), dump(v_real) FROM dual UNION
SELECT 5, 'number(5,2)', to_char(v_number), dump(v_number) FROM dual UNION
SELECT 6, 'char(1)', to_char(v_char), dump(v_char) FROM dual UNION
SELECT 7, 'nchar(1)', to_char(v_nchar), dump(v_nchar) FROM dual UNION
SELECT 8, 'varchar2(2)', to_char(v_varchar2), dump(v_varchar2) FROM dual UNION
SELECT 9, 'nvarchar2(2)', to_char(v_nvarchar2), dump(v_nvarchar2) FROM dual UNION
SELECT 10, 'varchar(1)', to_char(v_varchar), dump(v_varchar) FROM dual UNION
SELECT 11, 'date', to_char(v_date), dump(v_date) FROM dual UNION
SELECT 12, 'timestamp', to_char(v_timestamp), dump(v_timestamp) FROM dual UNION
SELECT 13, 'long', to_char(v_long), dump(v_long) FROM dual
) t;
end;
SELECT * FROM Temp01;
DROP TABLE Temp01;
從上圖可以看到,每種數據類型的字節占用情況,以及該類型代表的數字代碼:
1) 數字類型,type=2;
2) 固定長度字符類型,type=96;
3) 可變長度字符類型,type=1;
4) 日期類型,type=12;
5) 時間戳類型,type=180;