CHAR:這是一個定長字符串,會用空格填充來達到其最大長度。非null的CHAR(2) 老是包含2字節信息(使用了默認國家語言支持National Language Support,NLS設置)。CHAR字段最多能夠存儲2,000字節的信息。
NCHAR:這是一個包含UNICODE格式數據的定長字符串。Unicode是一種對字符進行編碼的通用方法,而不論使用的是何種計算機系統平臺。有了NCHAR類型,就容許數據庫中包含採用兩種不一樣字符集的數據:使用數據庫字符集的CHAR類型和使用國家字符集的NCHAR類型。非null的NCHAR(2)老是包含2個字符的信息(注意,在這方面,它與CHAR類型有所不一樣)。NCHAR字段最多能夠存儲2,000字節的信息。
VARCHAR2:VARCHAR的同義詞。這是一個變長字符串,與CHAR類型不一樣,它不會用空格填充至最大長度。VARCHAR2(12)可能包含0~12字節的信息(使用默認NLS設置)。VARCHAR2最多能夠存儲4,000字節的信息。
NVARCHAR2:這是一個包含UNICODE格式數據的變長字符串。NVARCHAR2(12)能夠包含0~12字符的信息。NVARCHAR2最多能夠存儲4,000字節的信息。
RAW:這是一種變長二進制數據類型,這說明採用這種數據類型存儲的數據不會發生字符集轉換。能夠把它看做由數據庫存儲的信息的二進制字節串。這種類型最多能夠存儲2,000字節的信息。
NUMBER:這種數據類型能存儲精度最多達38位的數字。每一個數存儲在一個變長字段中,其長度在0(尾部的NULL列就是0字節)~22字節之間。Oracle的NUMBER類型精度很高,遠遠高於許多編程語言中常規的FLOAT和DOUBLE類型。
BINARY_FLOAT:這是Oracle 10g Release 1及之後版本中才有的一種新類型。它是一個32位單精度浮點數,能夠支持至少6位精度,佔用磁盤上5字節的存儲空間。
LONG:這種類型能存儲最多2G的字符數據(2GB是指2千兆字節,而不是2千兆字符,由於在一個多字節字符集中,每一個字符可能有多個字節)。因爲LONG類型有許多限制,並且提供LONG類型只是爲了保證向後兼容性,因此強烈建議新應用中不要使用LONG類型,並且在現有的應用中也要儘量將LONG類型轉換爲CLOB類型。
LONG RAW:LONG RAW類型能存儲多達2GB的二進制信息。因爲LONG一樣的緣由,建議在未來的全部開發中都使用CLOB類型,另外現有的應用中也應儘量將LONG RAW轉換爲BLOB類型。
DATE:這是一個7字節的定寬日期/時間數據類型。總包含7個屬性,包括:世紀、世紀中哪一年、月份、月中的哪一天、小時、分鐘和秒。
TIMESTAMP:這是一個7字節或12字節的定寬日期/時間數據類型。它與DATE數據類型不一樣,由於TIMESTAMP能夠包含小數秒(fractional second);帶小數秒的TIMESTAMP在小數點右邊最多能夠保留9位。
TIMESTAMP WITH TIME ZONE:與前一種類型相似,這是一個12字節的定寬TIMESTAMP,不過它還提供了時區(TIME ZONE)支持。數據中會隨TIMESTAMP存儲有關時區的額外信息,因此原先插入的TIME ZONE會與數據一同保留。
TIMESTAMP WITH LOCAL TIME ZONE:與TIMESTAMP相似,這是一種7字節或12.字節的定寬日期/時間數據類型;不過,這種類型對時區敏感(time zone sensitive)。若是在數據庫中有修改,會參考數據中提供的TIME ZONE,根據數據庫時區對數據中的日期/時間部分進行「規範化」。
INTERVAL YEAR TO MONTH:這是一個5字節的定寬數據類型,用於存儲一個時間段,這個類型將時段存儲爲年數和月數。能夠在日期運算中使用這種時間間隔使一個DATE或TIMESTAMP類型增長或減小一段時間。
INTERVAL DAY TO SECOND:這是一個12字節的定寬數據類型,用於存儲一個時段,這個類型將時段存儲爲天/小時/分鐘/秒數,還能夠有最多9位的小數秒。
BFILE:這種數據類型容許在數據庫列中存儲一個Oracle目錄對象(操做系統目錄的一個指針)和一個文件名,並讀取這個文件。這實際上容許你以一種只讀的方式訪問數據庫服務器上可用的操做系統文件,就好像它們存儲在數據庫表自己中同樣。
BLOB:在Oracle9i及之前的版本中,這種數據類型容許存儲最多4GB的數據,在Oracle 10g及之後的版本中容許存儲最多(4GB)×(數據庫塊大小)字節的數據。BLOB包含不須要進行字符集轉換的「二進制「數據,適合存儲電子表格、字處理文檔、圖像文件等。
CLOB:容許存儲最多(4GB)×(數據庫塊大小)字節的數據。CLOB包含要進行字符集轉換的信息。很適合存儲純文本信息。
NCLOB:容許存儲最多(4GB)×(數據庫塊大小)字節的數據。NCLOB存儲用數據庫國家字符集編碼的信息,這些信息要進行字符集轉換。
ROWID:ROWID其實是數據庫中一行的12字節地址。ROWID中編碼有足夠的信息,足以在磁盤上定位這一行,以及標識ROWID指向的對象(表等)。
UROWID:UROWID是一個通用ROWID,用於表(如IOT和經過異構數據庫網關訪問的沒有固定ROWID的表)。UROWID是行主鍵值的一種表示,所以,取決於所指向的對象,UROWID的大小會有所變化。
以上列表中還少了許多類型,如INT、INTEGER、SMALLINT、FLOAT、REAL等。這些類型實際上都是在上表所列的某種類型的基礎上實現的,它們只是固有Oracle類型的同義詞。sql
Oracle中的字符數據類型包括CHAR、VARCHAR2以及帶「N「的相應」變體「(NCHAR和NVARCHAR2),這些字符數據類型能存儲2,000字節或4,000字節的文本。這些文本會由數據庫根據須要在不一樣字符集之間轉換。字符集(chrarcter set)是各個字符的一種二進制表示(用位和字節表示)。目前有多種不一樣的字符集,每種字符集能表示不一樣的字符,例如:
US7ASCII字符集是128字符的ASCII標準表示。它使用字節的低7位表示這128個字符。
WE8ISO8859P1字符集是一種西歐字符集,不只能不是128個ASCII字符,還能表示128個擴展字符,這個字符集使用了字節的所有8位。數據庫
國家語言支持(National Language Support)。NLS是數據庫的一個很是強大的特性,NLS控制着數據的許多方面。例如,它控制着數據如何存儲;還有咱們在數據中是會看到多個逗號和一個句號(如12.000,000.01),仍是會看到多個點號和一個逗號(如12.000.000,01)。編程
它控制着如下兩個方面:
文本數據持久存儲在磁盤上時如何編碼
透明地將數據從一個字符集轉換到另外一個字符集服務器
假設你在數據庫中用WE8ISO8859P1字符集存儲8位的數據,可是你的某些客戶使用的是一種7位字符集,如US7ASCII。這些客戶不想要8位的數據,須要從數據庫將數據轉換爲他們能用的形式。儘管聽上去不錯,可是若是你不知道會發生這種轉換,就會發現,過一段時間後,數據會「丟失「字符,WE8ISO8859P1字符集中的某些字符在US7ASCII中並無,這些字符會轉換爲US7ASCII中的某個字符。緣由就在於這裏發生了字符集轉換。簡而言之,若是你從數據庫獲取了使用字符集1的數據,將其轉換爲使用字符集2,再把這些數據插入回數據庫中(完成以上的逆過程),就極有可能大幅修改數據。字符集轉換過程一般會修改數據,而你每每會把一個較大的字符集(在此例中就是8位字符集)映射到一個較小的字符集(此例中的7位字符集)。這是一種有損轉換(lossy conversion),字符就會被修改,這只是由於:較小的字符集不可能表示較大字符集中的每個字符。可是這種轉換必須發生。若是數據庫以一種單字節字符集存儲數據,可是客戶(如一個Java應用,由於Java語言使用Unicode)但願數據採用多字節表示,就必須執行轉換,只有這樣客戶應用才能使用這些數據。編程語言
Oracle中有4種基本的字符串類型,分別是CHAR、VARCHAR二、NCHAR和NVARCHAR2。在Oracle中,全部串都以一樣的格式存儲。在數據庫塊上,最前面都有一個1~3字節的長度字段,其後纔是數據,若是數據爲NULL,長度字段則表示一個但字節值0xFF。
注意 Oracle中尾部的NULL列佔用0字節存儲空間,這說明,若是表中的「最後一列」爲NULL,Oracle不會爲之存儲任何內容。若是最後兩列都是NULL,那麼對這兩列都不會存儲任何內容。可是,若是位於NULL列以後的某個列要求爲not null(即不容許爲null),Oracle會使用null標誌來指示這個列缺乏值。ide
若是串的長度小於或等於250(0x01~0xFA),Oracle會使用1個字節來表示長度。對於全部長度超過250的串,都會在一個標誌字節0xFE後跟有兩個字節來表示長度。函數
scott@ORCL>create table t 2 ( char_column char(20), 3 varchar2_column varchar2(20) 4 ) 5 / 表已建立。 scott@ORCL>insert into t values ( 'Hello World', 'Hello World' ); 已建立 1 行。 scott@ORCL>select * from t; CHAR_COLUMN VARCHAR2_COLUMN -------------------- -------------------- Hello World Hello World scott@ORCL>select * from t where char_column = 'Hello World'; CHAR_COLUMN VARCHAR2_COLUMN -------------------- -------------------- Hello World Hello World scott@ORCL>select * from t where varchar2_column = 'Hello World'; CHAR_COLUMN VARCHAR2_COLUMN -------------------- -------------------- Hello World Hello World
到目前爲止,兩個列看上去好像是同樣的,但實際上這裏發生了一些隱式轉換,在與CHAR列比較時,CHAR(12)直接量('Hello World’)已經提高爲一個CHAR(20),並在其中填充了空格。這種轉換確定已經發生了,由於Hello World 與沒有尾部空格的Hello World並不相同。能夠確認這兩個串是大相徑庭的:工具
scott@ORCL>select * from t where char_column = varchar2_column; 未選定行
它們彼此並不相等。咱們要麼必須用空格填充VARCHAR2_COLUMN列,使其長度到達20字節,要麼必須從CHAR_COLUMN列截去尾部的空格,以下:ui
scott@ORCL>select * from t where trim(char_column) = varchar2_column; CHAR_COLUMN VARCHAR2_COLUMN -------------------- -------------------- Hello World Hello World scott@ORCL>select * from t where char_column = rpad( varchar2_column, 20 ); CHAR_COLUMN VARCHAR2_COLUMN -------------------- -------------------- Hello World Hello World
對於使用變長串的應用,綁定輸入時會出現問題,並且確定會獲得「沒有找到數據「之類的錯誤:編碼
scott@ORCL>variable varchar2_bv varchar2(20) scott@ORCL>exec :varchar2_bv := 'Hello World'; PL/SQL 過程已成功完成。 scott@ORCL>select * from t where char_column = :varchar2_bv; 未選定行 scott@ORCL>select * from t where varchar2_column = :varchar2_bv; CHAR_COLUMN VARCHAR2_COLUMN -------------------- -------------------- Hello World Hello World
在此,搜索VARCHAR2串成功了,可是搜索CHAR列未成功。VARCHAR2綁定變量不會像字符串直接量那樣提高爲CHAR(20)。要完成綁定,解決方案是使用CHAR類型:
scott@ORCL>variable char_bv char(20) scott@ORCL>exec :char_bv := 'Hello World'; PL/SQL 過程已成功完成。 scott@ORCL>select * from t where char_column = :char_bv; CHAR_COLUMN VARCHAR2_COLUMN -------------------- -------------------- Hello World Hello World scott@ORCL>select * from t where varchar2_column = :char_bv; 未選定行
不過,若是混合使用並匹配VARCHAR2和CHAR,你就會不斷地遭遇這個問題。不只如此,開發人員如今還必須在應用中考慮字段寬度。若是開發人員喜歡使用RPAD()技巧將綁定變量轉換爲某種能與CHAR字段比較的類型(固然,與截斷(TRIM)數據庫列相比,填充綁定變量的作法更好一些,由於對列應用函數TRIM很容易致使沒法使用該列上現有的索引),可能必須考慮到通過一段時間後列長度的變化。若是字段的大小有變化,應用就會受到影響,由於它必須修改字段寬度。
正是因爲如下這些緣由:定寬的存儲空間可能致使表和相關索引比日常大出許多,還伴隨着綁定變量問題,因此不管什麼場合我都會避免使用CHAR類型。即便是CHAR(1)字段(即單字符字段)也不建議使用CHAR類型。
VARCHAR2<SIZE><BYTE|CHAR> <SIZE>是介於1~4,000之間的一個數,表示最多佔用4,000字節的存儲空間。
CHAR(<SIZE><BYTE|CHAR>) <SIZE>是介於1~2,000之間的一個數,表示最多佔用2,000字節的存儲空間
NVARCHAR2(<SIZE>) <SIZE>是一個大於0的數,其上界由國家字符集指定
NCHAR(<SIZE>) <SIZE>是一個大於0的數,其上界由國家字符集指定
2. 字節或字符
VARCHAR2和CHAR類型支持兩種指定長度的方法:
用字節指定:VARCHAR2(12 byte)。這能支持最多12字節的數據, 在一個多字節字符集中,這可能這是兩個字符。
用字符指定:VARCHAR2(12 char)。這將支持最多12字符的數據,多是多達40字節的信息。
使用UTF8之類的多字節字符集時,建議你在VARCHAR2/CHAR定義中使用CHAR修飾符,也就是說,使用VARCHAR2(80 CHAR),而不是VARCHAR2(80),由於你的本意極可能是定義一個實際上能存儲80字符數據的列。
下面這個小例子展現了BYTE和CHAR之間的區別,並顯示出上界的做用。咱們將建立一個包括3列的表,前兩列的長度分別是1字節和1字符,最後一列是4,000字符。
scott@ORCL>select * 2 from nls_database_parameters 3 where parameter = 'NLS_CHARACTERSET'; PARAMETER VALUE ---------------- --------------------- NLS_CHARACTERSET AL32UTF8 scott@ORCL>create table t 2 ( a varchar2(1), 3 b varchar2(1 char), 4 c varchar2(4000 char) 5 ) 6 / 表已建立。
如今,若是想在這個表中插入一個UTF字符,這個字符長度爲2個字節,能夠觀察到如下結果:
scott@ORCL>insert into t (a) values (unistr('\00d6')); insert into t (a) values (unistr('\00d6')) * 第 1 行出現錯誤: ORA-12899: 列 "SCOTT"."T"."A" 的值太大 (實際值: 2, 最大值: 1)
這個例子展現了兩點:
1. VARCHAR2(1 byte)的單位是字節,而不是字符。這裏確實只有一個Unicode字符,可是它在一個字節中放不下。
2. 將應用從單字節定寬字符集移植到一個多字節字符集時,可能會發現原來在字段中能放下的文本如今卻沒法放下。
第二點的緣由是,在一個單字節字符集中,包含20個字符的字符串長度就是20字節,徹底能夠在一個VARCHAR2(20)中放下。不過,在一個多字節字符集中,20個字符的字符串長度能夠到達80字節(若是每一個字符用4個字節表示),這樣一來,20個Unicode字符極可能沒法在20個字節中放下。你可能會考慮將DDL修改成VARCHAR2(20 CHAR),或者在運行DDL建立表時使用前面提到的NLS_LENGTH_SEMANTICS會話參數。
scott@ORCL>insert into t (b) values (unistr('\00d6')); 已建立 1 行。 scott@ORCL>select length(b), lengthb(b), dump(b) dump from t; LENGTH(B) LENGTHB(B) DUMP ---------- ---------- ---- 1 2 Typ=1 Len=2: 195,150
這個INSERT成功了,並且能夠看到,所插入數據的長度(LENGTH)就是一個字符,全部字符串函數都以字符爲單位工做。這個字段的長度是一個字符,可是LENGTHB函數(字節長度)顯示這個字段佔用了2字節的存儲空間,另外DUMP函數顯示了這些字節究竟是什麼。這個例子展現了 VARCHAR2(N)並不必定存儲N個字符,而只是存儲N個字節。
人們常常遇到的另外一個問題是:VARCHAR2的最大字節長度爲4,000,而CHAR的最大字節長度爲2,000。
scott@ORCL>declare 2 l_data varchar2(4000 char); 3 l_ch varchar2(12 char) := unistr( '\00d6' ); 4 begin 5 l_data := rpad( l_ch, 4000, l_ch ); 6 insert into t ( c ) values ( l_data ); 7 end; 8 / declare * 第 1 行出現錯誤: ORA-01461: 僅能綁定要插入 LONG 列的 LONG 值 ORA-06512: 在 line 6
在此顯示出,一個4,000字符的字符串實際上長度爲8,000字節,這樣一個字符串沒法永久地存儲在一個VARCHAR2(4000 CHAR)字段中。這個字符串能放在PL/SQL變量中,由於在PL/SQL中VARCHAR2最大能夠到達32KB。不過,存儲在表中時,VARCHAR2則被硬性限制爲最多隻能存放4,000字節。咱們能夠成功地存儲其中2,000個字符:
scott@ORCL>declare 2 l_data varchar2(4000 char); 3 l_ch varchar2(12 char) := unistr( '\00d6' ); 4 begin 5 l_data := rpad( l_ch, 2000, l_ch ); 6 insert into t ( c ) values ( l_data ); 7 end; 8 / PL/SQL 過程已成功完成。 scott@ORCL>select length( c ), lengthb( c ) 2 from t 3 where c is not null; LENGTH(C) LENGTHB(C) ---------- ---------- 2000 4000
如上圖,它佔用了4,000字節的存儲空間。
它們與相應的VARCHAR2和CHAR是同樣的,只是有如下不一樣:
文本採用數據庫的國家字符集來存儲和管理,而不是默認字符集。
長度老是字符數,而CHAR/VARCHAR2可能會指定是字節仍是字符。
數據庫的國家字符集有兩個可取值:UTF8或AL16UTF16。這使得NCHAR和NVARCHAR類型很適於只存儲多字節數據。
Oracle除了支持文本,還支持二進制數據的存儲。CHAR和VARCHAR2類 型須要進行字符集轉換,而二進制數據不會作這種字符集轉換。所以,二進制數據類型適於存儲加密信息,加密數據不是「文本「, 而是原文本的一個二進制表示、包含二進制標記信息的字處理文檔,等等。若是數據庫不認爲這些數據是」文本「,這些數據就應該採用一種二進制數據類型來存儲,另外不該該應用字符集轉換的數據也要使用二進制數據類型存儲。
Oracle支持3種數據類型來存儲二進制數據:
RAW類型,它很適合存儲多達2,000字節的RAW數據。
BLOB類型,它支持更大的二進制數據。
LONG RAW類型,這是爲支持向後兼容性提供的,新應用不該考慮使用這個類型。
二進制RAW類型的語法很簡單:
RAW(<size>)
例如,如下代碼建立了一個每行能存儲12字節二進制信息的表:
scott@ORCL>create table t ( raw_data raw(16) ); 表已建立。
從磁盤上的存儲來看,RAW類型與VARCHAR2類型很類似。RAW類型是一個變長的二進制串,這說明前面建立的表T能夠存儲1~16字節的二進制數據。它不會像CHAR類型那樣用空格填充。
處理RAW數據時,它被隱式地轉換爲一個VARCHAR2類型,也就是說,諸如SQL*Plus之類的許多工具不會直接顯示RAW數據,而是會將其轉換爲一種十六進制格式來顯示。在如下例子中,咱們使用SYS_GUID()在表中建立了一些二進制數據,SYS_GUID()是一個內置函數,將返回一個全局唯一的16字節RAW串(GUID就表明全局唯一標識符,globally unique identifier):
scott@ORCL>insert into t values ( sys_guid() ); 已建立 1 行。 scott@ORCL>select * from t; RAW_DATA -------------------------------- A6A418FD9A6040A4B1DBB352CD5CBA9A
首先,RAW數據看上去就像是一個字符串。SQL*Plus就是以字符串形式獲取和打印RAW數據,可是RAW數據在磁盤上並不存儲爲字符串。SQL*Plus不能在屏幕上打印任意的二進制數據。要記住,二進制數據可能包含諸如回車或換行等控制字符,還多是一個Ctrl+G字符,這會致使終端發出「嘟嘟「的叫聲。
其次,RAW數據看上去遠遠大於16字節,實際上,在這個例子中,你會看到32個字符。這是由於,每一個二進制字節都顯示爲兩個十六進制字符。所存儲的RAW數據其實長度就是16字節,可使用Oracle DUMP函數確認這一點。在此,我「轉儲「了這個二進制串的值,並使用了一個可選參數來指定顯示各個字節值時應使用哪種進制。這裏使用了基數16,從而能將轉儲的結果與前面的串進行比較:
scott@ORCL>select dump(raw_data,16) from t; DUMP(RAW_DATA,16) ---------------------------------------- Typ=23 Len=16: a6,a4,18,fd,9a,60,40,a4,b1,db,b3,52,cd,5c,ba,9a
DUMP顯示出,這個二進制串實際上長度爲16字節(LEN=16),另外還逐字節地顯示了這個二進制數據。能夠看到,這個轉儲顯示與SQL*Plus將RAW數據獲取爲一個串時所執行的隱式轉換是匹配的。另外一個反向上(插入)也會執行隱式轉換:
scott@ORCL>insert into t values ( 'abcdef' ); 已建立 1 行。
這不會插入串abcdef,而會插入一個3字節的RAW數據,其字節分別是AB、CD、EF,若是用十進制表示則爲字節17一、20五、239。若是試圖使用一個包含非法16進制字符的串,就會收到一個錯誤消息:
scott@ORCL>select dump(raw_data,16) from t; DUMP(RAW_DATA,16) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------------------------------------- Typ=23 Len=16: a6,a4,18,fd,9a,60,40,a4,b1,db,b3,52,cd,5c,ba,9a Typ=23 Len=3: ab,cd,ef scott@ORCL>insert into t values ( 'abcdefgh' ); insert into t values ( 'abcdefgh' ) * 第 1 行出現錯誤: ORA-01465: 無效的十六進制數字
RAW類型能夠加索引,還能在謂詞中使用,它與其餘任何數據類型有一樣的功能。不過,必須小心避免不但願的隱式轉換,並且必須知道確實會發生隱式轉換。
可使用如下內置函數來執行這種操做:
HEXTORAW:將十六進制字符串轉換爲RAW類型
RAWTOHEX:將RAW串轉換爲十六進制串
SQL*Plus將RAW類型獲取爲一個串時,會隱式地調用RAWTOHEX函數,而插入串時會隱式地調用HEXTORAW函數。應該避免隱式轉換,而在編寫代碼時老是使用顯示轉換,這是一個很好的實踐作法。因此前面的例子應該寫做:
scott@ORCL>select rawtohex(raw_data) from t; RAWTOHEX(RAW_DATA) ---------------------------------------------------------------- A6A418FD9A6040A4B1DBB352CD5CBA9A ABCDEF scott@ORCL>insert into t values ( hextoraw('abcdef') ); 已建立 1 行。 scott@ORCL>select rawtohex(raw_data) from t; RAWTOHEX(RAW_DATA) ---------------------------------------------------------------- A6A418FD9A6040A4B1DBB352CD5CBA9A ABCDEF ABCDEF