sqlite字段類型

聲明:本文copy自博客園-殘星的博客,博客地址:http://www.cnblogs.com/mingforyou/archive/2013/02/19/2917122.html

存儲類(Storage Classes)

如前文所述,SQLite在處理數據類型時與其它的數據庫不同。區別在於它所支持的類型以及這些類型是如何存儲、比較、強化(enforc)和指派(assign)。下面各節介紹SQLite處理數據類型的獨特方法和它與域完整性的關係。

對於數據類型,SQLite的域完整性被稱爲域親和性(affinity)更合適。在SQLite中,它被稱爲類型親和性(type affinity)。爲了理解類型親和性,你必須先要理解存儲類和弱類型(manifesttyping)。

SQLite有5個原始的數據類型,被稱爲存儲類。存儲類這個詞表明瞭一個值在磁盤上存儲的格式,其實就是類型或數據類型的同義詞。這5個存儲類在表4-6中描述。

表 4-6 SQLite存儲類

                       

 

名稱

 
 

說明

 
 

INTEGER

 
 

整數值是全數字(包括正和負)。整數可以是1, 2, 3, 4, 6或 8字節。整數的最大範圍(8 bytes)是{-9223372036854775808, 0, +9223372036854775807}。SQLite根據數字的值自動控制整數所佔的字節數。

 

空注:參可變長整數的概念。

 
 

REAL

 
 

實數是10進制的數值。SQLite使用8字節的符點數來存儲實數。

 
 

TEXT

 
 

文本(TEXT)是字符數據。SQLite支持幾種字符編碼,包括UTF-8和UTF-16。字符串的大小沒有限制。

 
 

BLOB

 
 

二進制大對象(BLOB)是任意類型的數據。BLOB的大小沒有限制。

 
 

NULL

 
 

NULL表示沒有值。SQLite具有對NULL的完全支持。

 

SQLite通過值的表示法來判斷其類型,下面就是SQLite的推理方法:

l  SQL語句中用單引號或雙引號括起來的文字被指派爲TEXT。

l  如果文字是未用引號括起來的數據,並且沒有小數點和指數,被指派爲INTEGER。

l  如果文字是未用引號括起來的數據,並且帶有小數點或指數,被指派爲REAL。

l  用NULL說明的值被指派爲NULL存儲類。

l  如果一個值的格式爲X'ABCD',其中ABCD爲16進制數字,則該值被指派爲BLOB。X前綴大小寫皆可。

SQL函數typeof()根據值的表示法返回其存儲類。使用這個函數,下面SQL語句返回的結果爲:

sqlite> select typeof(3.14),typeof('3.14'), typeof(314), typeof(x'3142'), typeof(NULL);

typeof(3.14)   typeof('3.14')  typeof(314)    typeof(x'3142')       typeof(NULL)

real                text                integer           blob                      null

 

SQLite單獨的一個字段可能包含不同存儲類的值。請看下面的示例:

sqlite> DROP TABLE domain;

sqlite> CREATE TABLE domain(x);

sqlite> INSERT INTO domain VALUES(3.142);

sqlite> INSERT INTO domain VALUES('3.142');

sqlite> INSERT INTO domain VALUES(3142);

sqlite> INSERT INTO domain VALUES(x'3142');

sqlite> INSERT INTO domain VALUES(NULL);

sqlite> SELECT ROWID, x, typeof(x) FROMdomain;

返回結果爲:

rowid      x            typeof(x)

1            3.142      real

2            3.142      text

3            3142     integer

4            1B        blob

5            NULL    null

這帶來一些問題。這種字段中的值如何存儲和比較?如何對一個包含了INTEGER、REAL、TEXT、BLOB和NULL值的字段排序?一個整數和一個BLOB如何比較?哪個更大?它們能相等嗎?

答案是:具有不同存儲類的值可以存儲在同一個字段中。可以被排序,因爲這些值可以相互比較。有完善定義的規則來做這件事。不同存儲類的值可以通過它們各自類的“類值”進行排序,定義如下:

1. NULL存儲類具有最低的類值。一個具有NULL存儲類的值比所有其它值都小(包括其它具有NULL存儲類的值)。在NULL值之間,沒有特別的可排序值。

2. INTEGER或REAL存儲類值高於NULL,它們的類值相等。INTEGER值和REAL值通過其數值進行比較。

3. TEXT存儲類的值比INTEGER和REAL高。數值永遠比字符串的值低。當兩個TEXT值進行比較時,其值大小由“排序法”決定。

4. BLOB存儲類具有最高的類值。具有BLOB類的值大於其它所有類的值。BLOB值之間在比較時使用C函數memcmp()。

所以,當SQLite對一個字段進行排序時,首先按存儲類排序,然後再進行類內的排序 (NULL類內部各值不必排序) 。下面的SQL說明了存儲類值的不同:

sqlite> SELECT 3 < 3.142, 3.142 <'3.142', '3.142' < x'3000', x'3000' < x'3001';

返回:

3 < 3.142              3.142 < '3.142'              '3.142'< x'3000'     x'3000' < x'3001'

1                   1                          1                          1

 

弱類型(manifest typing)

SQLite使用弱類型。

看下面的表:

CREATE TABLE foo( x integer,

    y text, z real );

向該表插入一條記錄:

INSERT INTO foo VALUES ('1', '1', '1');

當SQLite創建這條記錄時,x、y和z這3個字段中存儲的是什麼類型呢?答案是INTEGER, TEXT和REAL。

 

再看下面例子:

CREATE TABLE foo(x, y, z);

現在執行同樣的插入語句:

INSERT INTO foo VALUES ('1', '1', '1');

現在,x、y和z中存儲的是什麼類型呢?答案是TEXT、TEXT和TEXT。

那麼,是否SQLite的字段類型默認爲TEXT呢?再看,還是第2個表,執行如下插入語句:

INSERT INTO foo VALUES (1, 1.0, x'10');

現在,x、y和z中存儲的是什麼類型呢?答案是INTEGER、REAL和BLOB。

 

如果你願意,可以爲SQLite的字段定義類型,這看起來跟其它數據庫一樣。但這不是必須的,你可以儘管違反類型定義。這是因爲在任何情況下,SQLite都可以接受一個值並推斷它的類型。

總之,SQLite的弱類型可表示爲:1)字段可以有類型,2)類型可以通過值來推斷。類型親和性介紹這兩個規定如何相互關聯。所謂類型親和性就是在強類型(strict typing)和動態類型(dynamic typing)之間的平衡藝術。

類型親和性(Type Affinity)

在SQLite中,字段沒有類型或域。當給一個字段聲明瞭類型,該字段實際上僅僅具有了該類型的新和性。聲明類型和類型親和性是兩回事。類型親和性預定 SQLite用什麼存儲類在字段中存儲值。在存儲一個給定的值時到底SQLite會在該字段中用什麼存儲類決定於值的存儲類和字段親和性的結合。我們先來介紹一下字段如何獲得它的親和性。

字段類型和親和性

首先,每個字段都具有一種親和性。共有四種親和性:NUMERIC、INTEGER、TEXT和NONE。一個字段的親和性由它預聲明的類型決定。所以,當你爲字段聲明瞭類型,從根本上說是爲字段指定了親和性。SQLite按下面的規則爲字段指派親和性:

l  默認的,一個字段默認的親和性是NUMERIC。如果一個字段不是INTEGER、TEXT或NONE的,那它自動地被指派爲NUMERIC親和性。

l  如果爲字段聲明的類型中包含了'INT'(無論大小寫),該字段被指派爲INTEGER親和性。

l  如果爲字段聲明的類型中包含了'CHAR'、'CLOB'或'TEXT'(無論大小寫),該字段被指派爲TEXT親和性。如'VARCHAR'包含了'CHAR',所以被指派爲TEXT親和性。

l  如果爲字段聲明的類型中包含了'BLOB'(無論大小寫),或者沒有爲該字段聲明類型,該字段被指派爲NONE親和性。

注意:如果沒有爲字段聲明類型,該字段的親和性爲NONE,在這種情況下,所有的值都將以它們本身的(或從它們的表示法中推斷的)存儲類存儲。如果你暫時還不確定要往一個字段裏放什麼內容,或準備將來修改,用NONE親和性是一個好的選擇。但SQLite默認的親和性是NUMERIC。例如,如果爲一定字段聲明瞭類型JUJYFRUIT,該字段的親和性不是NONE,因爲SQLite不認識這種類型,會給它指派默認的NUMERIC親和性。所以,與其用一個不認識的類型最終得到NUMERIC親和性,還不如不爲它指定類型,從而使它得到NONE親和性。

親和性和存儲

親和性對值如何存儲到字段有影響,規則如下:

l  一個NUMERIC字段可能包括所有5種存儲類。一個NUMERIC字段具有數字存儲類的偏好(INTEGER和REAL)。當一個TEXT值被插入到一個NUMERIC字段,將會試圖將其轉化爲INTEGER存儲類;如果轉化失敗,將會試圖將其轉化爲REAL存儲類;如果還是失敗,將會用TEXT存儲類來存儲。

l  一個INTEGER字段的處理很像NUMERIC字段。一個INTEGER字段會將REAL值按REAL存儲類存儲。也就是說,如果這個REAL值沒有小數部分,就會被轉化爲INTEGER存儲類。INTEGER字段將會試着將TEXT值按REAL存儲;如果轉化失敗,將會試圖將其轉化爲INTEGER存儲類;如果還是失敗,將會用TEXT存儲類來存儲。

l  一個TEXT字段將會把所有的INTEGER或REAL值轉化爲TEXT。

l  一個NONE字段不試圖做任何類型轉化。所有值按它們本身的存儲類存儲。

l  沒有字段試圖向NULL或BLOB值轉化——如無論用什麼親和性。NULL和BLOB值永遠都按本來的方式存儲在所有字段。

這些規則初看起來比較複雜,但總的設計目標很簡單,就是:如果你需要,SQLite會盡量模仿其它的關係型數據庫。也就是說,如果你將SQLite看成是一個傳統數據庫,類型親和性將會按你的期望來存儲值。如果你聲明瞭一個INTEGER字段,並向裏面放一個整數,就會按整數來存儲。如果你聲明瞭一個具有 TEXT, CHAR或VARCHAR類型的字段並向裏放一個整數,整數將會轉化爲TEXT。可是,如果你不遵守這些規定,SQLite也會找到辦法來存儲你的值。

親和性的運行

讓我們看一些例子來了解親和性是如何工作的:

sqlite> CREATE TABLE domain(i int, nnumeric, t text, b blob);

sqlite> INSERT INTO domain VALUES(3.142,3.142,3.142,3.142);

sqlite> INSERT INTO domain VALUES('3.142','3.142','3.142','3.142');

sqlite> INSERT INTO domain VALUES(3142,3142,3142,3142);

sqlite> INSERT INTO domain VALUES(x'3142',x'3142',x'3142',x'3142');

sqlite> INSERT INTO domain VALUES(null,null,null,null);

sqlite> SELECT ROWID,typeof(i),typeof(n),typeof(t),typeof(b)FROM domain;

返回:

rowid      typeof(i)  typeof(n) typeof(t)  typeof(b)

1            real         real         text         real

2            real         real         text         text

3            integer    integer    text         integer

4            blob        blob        blob        blob

5            null         null         null         null

下面的SQL說明存儲類的排序情況:

sqlite> SELECT ROWID, b, typeof(b) FROMdomain ORDER BY b;

返回:

rowid b typeof(b)

5 NULL null

1 3.142 real

3 3142 integer

2 3.142 text

4 1B blob

sqlite> SELECT ROWID, b, typeof(b),b<1000 FROM domain ORDER BY b;

返回:

rowid b typeof(b) b<1000

NULL null NULL

1 3.142 real 1

3 3142 integer 1

2 3.142 text 0

4 1B blob 0

存儲類和類型轉換

關於存儲類,需要關注的另一件事是:存儲類有時會影響到值如何進行比較。特別是SQLite有時在進行比較之前,會將值在數字存儲類(INTEGER和REAL)和TEXT之間進行轉換。爲進行二進制的比較,遵循如下規則:

l  當一個字段值與一個表達式的結果進行比較,字段的親和性會在比較之前應用於表達式的結果。

l  當兩個字段值進行比較,如果一個字段擁有INTEGER或NUMERIC親和性而另一個沒有,NUMERIC親和性會應用於非NUMERIC字段的TEXT值。

l  當兩個表達式進行比較,SQLite不做任何轉換。如果兩個表達式有相似的存儲類,則直接按它們的值進行比較;否則按類值進行比較。

請看下面例子:

sqlite> selectROWID,b,typeof(i),i>'2.9' from domain ORDER BY b;

rowid b typeof(i i>'2.9'

5 NULL null NULL

1 3.142 real 1

3 3142 integer 1

2 3.142 real 1

4 1B blob 1

也算是“強類型(STRICT TYPING)”

如果你需要比類型親和性更強的域完整性,可以使用CHECK約束。你可以使用一個單獨的內置函數和一個CHECK約束來實現一個“假的”強類型。

發佈了22 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章