SQLite數據類型

大多數 SQL 數據庫引擎(據我們所知,除 SQLite 之外的所有SQL 數據庫引擎)都使用嚴格的靜態類型。使用靜態類型,值的類型便由它的容器 --存儲值的特定的列 --來決定。

SQLite 使用更通用的動態類型系統。在SQLit 中,值的數據類型與值本身相關,而不是與它的容器。SQLite的動態類型系統與其它數據庫引擎的常用靜態類型系統是向後兼容的,在這個意義上,工作在靜態類型數據庫上的SQL 語句應該以同樣的方式工作在SQLite 中。然而,SQLite中的動態類型允許它做傳統的嚴格類型的數據庫所不能做的事。

1.0 存儲類型與數據類型

存儲在 SQLite 數據庫中的每個值(或是由數據庫引擎所操作的值)都有一個以下的存儲類型:

1     NULL. 值是空值。

2     INTEGER. 值是有符號整數,根據值的大小以12346 8字節存儲。

3     REAL. 值是浮點數,以8字節IEEE 浮點數存儲。

4     TEXT. 值是文本字符串,使用數據庫編碼(UTF-8,UTF-16BE UTF-16LE)進行存儲。

5     BLOB. 值是一個數據塊,按它的輸入原樣存儲。

注意,存儲類型比數據類型更籠統。以 INTEGER 存儲類型爲例,它包括6種不同的長度不等的整數類型,這在磁盤上是不同的。但是隻要INTEGER 值從磁盤讀取到內存進行處理,它們就被轉換爲更爲一般的數據類型(8字節有符號整型)。因此在一般情況下,存儲類型數據類型沒什麼差別,這兩個術語可以互換使用。

SQLite 版本3數據庫中的任何列,除了整型主鍵列,都可用於存儲任何存儲類型的值。

SQL 語句中的任何值,無論它們是嵌入到SQL 語句中的字面量還是綁定到預編譯SQL 語句中的參數,都有一個隱含的存儲類型。在下述情況下,數據庫引擎會在執行查詢時在數值存儲類型(INTEGERREAL)和TEXT 之間進行轉換。

1.1 布爾類型

SQLite 並沒有單獨的布爾存儲類型,而是將布爾值存儲爲整數 0(false) 1(true)

1.2 日期和時間類型

SQLite 沒有另外的存儲類型來存儲日期和時間。SQLite的內置的日期和時間函數能夠將日期和時間存爲TEXTREALINTEGER 值:

1     TEXT  ISO8601 字符串 ("YYYY-MM-DD HH:MM:SS.SSS")

2     REAL 儒略日數(Julian Day Numbers),按照前公曆,自格林威治時間公元前47141124日中午以來的天數。

3     INTEGER Unix 時間,自1970-01-01 00:00:00 UTC 以來的秒數。

應用可以選擇這些格式中的任一種存儲日期和時間,並使用內置的日期和時間函數在這些格式間自由轉換。

2.0 類型親和性

爲了最大限度地提高 SQLite 和其它數據庫引擎之間的兼容性,SQLite支持列的類型親和性的概念。列的類型親和性是指數據存儲於該列的推薦類型。這裏重要的思想是類型是推薦的,而不是必須的。任何列仍可以存儲任何類型的數據。這只是讓一些列有選擇性地優先使用某種存儲類型。一個列的首選存儲類型被稱爲它的親和性

每個 SQLite 3 數據庫中的列都歸於以下的類型親和性中的一種:

1     TEXT

2     NUMERIC

3     INTEGER

4     REAL

5     NONE

一個具有 TEXT 親和性的列使用存儲類型 NULLTEXT BLOB 存儲所有數據。如果數值數據被插入到一個具有TEXT 親和性的列,則數據在存儲前被轉換爲文本形式。

數值親和性的列可能包含了使用所有五個存儲類的值。當插入文本數據到數值列時,該文本的存儲類型被轉換成整型或實數(按優先級排序)如果這種轉換是無損或可逆的的話。對於文本與實數類型之間的轉換,如果前15個重要十進制數字被保留的話,SQLite認爲這種轉換是無損並可逆的。如果文本不能無損地轉換成整型或實數,那這個值將以文本類型存儲。不要試圖轉換NULLBLOB值。

一個字符串可能看上去像帶有小數點和/或指數符的浮點文字,但只要這個值可以用一個整型表示,數值親和性就會把它轉換成一個整型。因此,字符串‘3.0e+5'以整型300000,而不是浮點值30000.0的形式存儲在一個數值親和性的列裏。

 

一個使用整型親和性的列與具有數值親和性的列表現一致。只是在CAST表達式裏,它們之間的區別體現得明顯。

除了強制將整型值轉換成浮點表示外,一個具有實數親和性的列與具有數值親和性的列表現一致(作爲一個內部的優化,爲了少佔用空間,無小數部分且存儲在實數親和性列上的小浮點值以整型形式寫到磁盤,讀出時自動轉換回浮點值。在SQL級別,這種優化是完全不可見的,並且只能通過檢查數據庫文件的原始比特檢測到)。

一個具有NONE親和性的列不能從一種存儲類型轉換成另一種,也不要試圖強制對它進行轉換。

2.1 列親和性測定

列的親和性是由它的聲明類型決定的,按照以下順序所示的規則:

1. 如果聲明類型包含字符串“INT”,那它被指定爲整型親和性;

2. 如果列的聲明類型包含任何“CHAR”“CLOB”“TEXT”字符串,那麼該列具有文本親和性。注意:VARCHAR類型包含“CHAR”並且被指定爲文本親和性;

3. 如果列的聲明類型包含“BLOB”或者沒有指定類型,那這列具有NONE親和性;

4. 如果列的聲明類型包含任何“REAL”“FLOA”“DOUB”字符串,則該列具有實數親和性;

5. 否則,它將具有數值親和性。

注意:判定列親和性規則的順序是很重要的。一個具有“CHARINT”聲明類型的列將匹配規則12,但是規則1優先所有該列具有整型親和性。

2.2 親和性名字實例

下表顯示了有多少從更傳統的SQL實現的常用數據類型名,通過上一節介紹的五個規則被轉換成各種親和性類型。這張表只顯示了SQLite可接受的一小部分數據類型名。注意:跟在類型名後,括號內數值參數(如:VARCHAR255))將被SQLite忽略 -SQLite不對字符串、BLOBs或數值的長度強加任何限制(除了大型全局SQLITE_MAX_LENGTH限制)。

spacer.gif

注意:因爲在“POINT”末尾的“INT”,一個“ FLOATING POINT”聲明類型會被賦予整型親和性,而不是實數親和性。而且“STRING”聲明類型具有數值親和性,而不是文本親和性。

2.3 列親和性行爲實例

以下SQL演示當有值插入到一張表時,SQLite如何使用列親和性實現類型轉換的:

 

?

1

2

3

4

5

6

7

CREATE TABLE  t1(

  t  TEXT,   -- text affinity by rule 2

  nu  NUMERIC, --  numeric affinity by rule 5

  i  INTEGER, --  integer affinity by rule 1

  r  REAL,   -- real affinity by rule 4

  no BLOB   --  no affinity by rule 3

);

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

-- Values stored as TEXT, INTEGER, INTEGER, REAL, TEXT.(值分別以文本、整型、整型、實數、文本形式存儲)

INSERT INTO  t1 VALUES('500.0',  '500.0', '500.0',  '500.0', '500.0');

SELECT typeof(t), typeof(nu), typeof(i),  typeof(r), typeof(no) FROM t1;

text|integer|integer|real|text

  

-- Values stored as TEXT, INTEGER, INTEGER, REAL, REAL.

DELETE FROM  t1;

INSERT INTO  t1 VALUES(500.0, 500.0, 500.0,  500.0, 500.0);

SELECT typeof(t), typeof(nu), typeof(i),  typeof(r), typeof(no) FROM t1;

text|integer|integer|real|real

  

-- Values stored as TEXT, INTEGER, INTEGER, REAL, INTEGER.

DELETE FROM  t1;

INSERT INTO  t1 VALUES(500, 500, 500, 500, 500);

SELECT typeof(t), typeof(nu), typeof(i),  typeof(r), typeof(no) FROM t1;

text|integer|integer|real|integer

  

-- BLOBs are always stored as BLOBs regardless of column affinity.  DELETE FROM t1;

INSERT INTO  t1 VALUES(x'0500',  x'0500', x'0500',  x'0500', x'0500');

SELECT typeof(t), typeof(nu), typeof(i),  typeof(r), typeof(no) FROM t1;

blob|blob|blob|blob|blob

  

-- NULLs are also unaffected by affinity

DELETE FROM  t1;

INSERT INTO  t1 VALUES(NULL,NULL,NULL,NULL,NULL);

SELECT typeof(t), typeof(nu), typeof(i),  typeof(r), typeof(no) FROM t1;

null|null|null|null|null

3.0 比較表達式

同標準SQL一樣,SQLite 3支持如下的比較操作符:"=","==", "<", "<=", ">",">=", "!=", "<>", "IN","NOT IN", "BETWEEN", "IS", 以及"IS NOT"

3.1 排序規則

比較的結果與操作數的存儲類型有關,同時依據以下的規則:

1     NULL值小於其他任何值(包括另外一個NULL

2     INTEGERREAL小於TEXTBLOB值;若兩個INTEGER(或者REAL)比較,則按照實際的數值進行。

3     TEXT小於BLOB,若兩個TEXT比較,結果則由適當的整理順序決定

4     若兩個BLOD比較,與memcmp()的結果一致

3.2 操作數進行比較時的相似性

在進行值的比較之前,SQLite會嘗試在存儲類INTEGERREAL/TEXT之間進行值的轉換。在比較之前嘗不嘗試進行轉換完全取決於操作數的相似性。操作數相似性的判定規則如下:

1     只是對一個列中的值進行引用的表達式同被引用的列具有完全相同的相似性。注意,如果XY.Z代表的是列的名稱,那麼+X+Y.Z可以認爲是爲了判定其相似性的表達式。

2     "CAST(expr AS type)"所表示的表達式同類型定義爲"type"的列具有完全相同的相似性。

3     其它情況下的表達式具有NONE相似性。

 

3.3 比較前的類型轉換

應用相似性"applyaffinity")的意思是,當且僅當所涉及的轉換是無損且可逆的情況下,將一個操作數轉換爲某特定的存儲類型。在進行比較之前對比較運算符的操作數應用相似性的規則如下按順序所示:

1     如果其中的一個操作數具有INTEGERREAL或者NUMERIC相似性而另外一個操作數具有TEXT或者NONE相似性,那麼就要對這另外一個操作數應用NUMERIC相似性。

2     如果其中的一個操作數具有TEXT相似性而另外一個具有NONE相似性,那麼就要對這另外一個操作數應用TEXT相似性。

3     其它情況下不會應用任何相似性,兩個操作數按照各自的原樣進行比較。

將表達式"a BETWEEN b AND c"看作兩個單獨的二元比較運算"a>= b AND a <= c",即使這麼一來,可能會造成其中的a在兩次比較中會被應用不同的相似性,也要這麼處理。Datatypeconversions in comparisons of the form "x IN (SELECT y ...)"這種形式的比較中,數據類型的轉換完全同"x=y"一樣進行處理。表達式"aIN (x, y, z, ...)" "a = +x OR a = +y OR a = +z OR ..."等價。換句話說,IN運算符右側的值(本例中就是"x","y", and "z")被看作是無相似性的,即使它們湊巧是某列的值或者是CAST表達式。

3.4 比較示例 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

CREATE TABLE  t1(

  a  TEXT,   -- text affinity

  b  NUMERIC-- numeric affinity

  c  BLOB,   -- no affinity

  d       -- no affinity

);

  

-- Values will be stored as TEXT, INTEGER, TEXT, and INTEGER  respectively

INSERT INTO  t1 VALUES('500',  '500', '500',  500);

SELECT typeof(a), typeof(b), typeof(c),  typeof(d) FROM t1;

text|integer|text|integer

  

-- Because column "a" has text affinity, numeric values on the

-- right-hand side of the comparisons are converted to text before

-- the comparison occurs.

SELECT a < 40,  a < 60,  a <  600 FROM t1;

0|1|1

  

-- Text affinity is applied to the right-hand operands but since

-- they are already TEXT this is a no-op; no conversions occur.

SELECT a < '40',  a < '60', a < '600'  FROM t1;

0|1|1

  

-- Column "b" has numeric affinity and so numeric affinity is  applied

-- to the operands on the right. Since the operands are already numeric,

-- the application of affinity is a no-op; no conversions occur. All

-- values are compared numerically.

SELECT b < 40,  b < 60,  b <  600 FROM t1;

0|0|1

  

-- Numeric affinity is applied to operands on the right, converting them

-- from text to integers. Then a numeric comparison occurs.

SELECT b < '40',  b < '60', b < '600'  FROM t1;

0|0|1

  

-- No affinity conversions occur. Right-hand side values all have

-- storage class INTEGER which are always less than the TEXT values

-- on the left.

SELECT c < 40,  c < 60,  c <  600 FROM t1;

0|0|0

  

-- No affinity conversions occur. Values are compared as TEXT.

SELECT c < '40',  c < '60', c < '600'  FROM t1;

0|1|1

  

-- No affinity conversions occur. Right-hand side values all have

-- storage class INTEGER which compare numerically with the INTEGER

-- values on the left.

SELECT d < 40,  d < 60,  d <  600 FROM t1;

0|0|1

  

-- No affinity conversions occur. INTEGER values on the left are

-- always less than TEXT values on the right.

SELECT d < '40',  d < '60', d < '600'  FROM t1;

1|1|1

若示例中的比較被替換——例如"a<40"被寫作"40>a"——所有的結果依然相同相同。

4.0 操作符

所有的數學運算符(+, -, *, /, %, <<,>>, &, and |)在展開前會將兩個操作數放入 NUMERIC 儲存類。即使這個過程是有損和不可逆轉的。一個 NULL 操作數在數學運算符上產生一個NULL 結果。在數算運算符上的操作數不被視爲數字,NULL並不會被轉爲00.0

5.0 排序, 分組組合查詢

當查詢結果使用 ORDER BY 子句排序時, 存儲類型的NULL空值是排在第一位的, 其次是INTEGER和散佈在數字順序的REAL數據, 其次是按照覈對序列順序的TEXT, 最後爲memcmp()order BLOB. 排序之前不會出現任何存儲類型轉換.

當使用GROUP BY 子句分組時不同類型的值被認爲是不同的數據, 除了INTEGERREAL 值如果他們數值相等則被認爲是相同的的數據. 沒有任何親和性適用於GROUPBY 子句結果的任意值.

組合查詢使用 UNION, INTERSECT EXCEPT 在數據之間執行隱式的比較. 沒有任何親和性適用於與UNION,INTERSECT, 或者EXCEPT關聯的隱式比較的運算數 - 數據的比較就像這樣.

6.0 整理序列

SQLite 比較兩個字符串時,它使用一個整理序列或整理函數(一物兩表)來決定當兩個字符串相同時,哪個字符串值更高。SQLite擁有三個內建整理函數:BINARY,NOCASE, RTRIM

1     BINARY - 使用memcmp() 比較字符串,無視文本編碼。

2     NOCASE - 與二進制比較相同,除了ASCII 26個大寫字母在比較前將會轉爲其小寫形勢。注意,只有ASCII 字符會大小寫轉化。由於表大小的需求,SQLite並不會嘗試UTF 大小寫轉化。

3     RTRIM - 與二進制比較相同,除了尾部空格符將被忽略。

應用可以通過 sqlite3_create_collation() 接口註冊額外的整理函數。

6.1 設定SQL中的排列順序

每個表中的每一個列都具有一個相關的排序函數。如果沒有顯式地定義排序函數,那麼,就會缺省使用BINARY作爲排序函數。列定義中的COLLATE子句可爲列定義一個可選的排序函數。

對於二元比較運算符(=, <, >, <=, >=,!=, IS, and IS NOT)來說,判定到底使用哪個排序函數的規則按順序如下所列:

1     如果兩個操作數中有任意一個操作數具有使用後綴COLLATE運算符顯式定義的排序函數,那麼就會用該函數進行比較,如果兩個操作數都有的情況下,優先使用左操作數的排序函數。

2     如果兩個操作數中任意一個操作數是一個列,那麼就會使用該列的排序函數進行比較,但在兩個操作數都是列的情況下,優先使用左操作數對應的列的排序函數。爲了達到這句話的目的,列名前帶有1個或多個一元運算符"+"的,仍然按原列名處理。

3     其它情況下,採用BINARY排序函數進行比較。

比較運算中的操作數,如果在它的任何子表達式中使用了後綴COLLATE運算符,就可以認爲是具有顯式的排序函數(上文中的規則1)。再者,如果在比較表達式中的任何地方使用了COLLATE運算符,那麼該運算符所定義的排序函數就會用於字符串的比較,而無論在表達式中出現了表中的哪一列。如果在比較中的任何地方出現了兩個或多個COLLATE運算符子表達式,無論在表達式中嵌入得多深,也無論表達式是怎麼使用括號的,都會使用出現在最左側的顯式排序函數。

表達式"x BETWEEN y and z"從邏輯上講,同"x>= y AND x <= z"這兩個比較運算完全等價,在使用排序函數時它們倆要象兩個本來就是獨立的比較運算一樣進行處理。在判定排列順序時,表達式"xIN (SELECT y ...)"處理方式完全同表達式"x = y"一樣,形如"x IN (y, z, ...)"的表達式,排列順序完全同X的排列順序一樣。

作爲 SELECT語句的一個部分,ORDER BY子句中排序條件也可以通過使用COLLATE運算符設定排列順序,如果設定了排序時就要按照設定的排序函數進行排序。否則,如果ORDERBY子句使用的排序表達式是一個列,那麼該列的排列順序就用於判定排列順序。如果該排序表達式不是列並且也無COLLATE子句,就會使用BINARY排列順序。

6.2 整理序列示例

下面的示例將識別整理序列,決定 SQL 語句的文本比較結果。注意,在文本比較時,如果是數字,二進制或Null值,整理序列可能並沒有被使用。

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

CREATE TABLE  t1(

  x  INTEGER PRIMARY  KEY,

  a,          /* collating sequence BINARY */

  b  COLLATE BINARY,  /* collating sequence BINARY */

  c  COLLATE RTRIM,  /* collating sequence RTRIM */

  d  COLLATE NOCASE  /* collating sequence NOCASE */

);

          /*  x  a   b   c    d */

INSERT INTO  t1 VALUES(1,'abc','abc', 'abc ','abc');

INSERT INTO  t1 VALUES(2,'abc','abc', 'abc', 'ABC');

INSERT INTO  t1 VALUES(3,'abc','abc', 'abc ', 'Abc');

INSERT INTO  t1 VALUES(4,'abc','abc ','ABC', 'abc');

  

/*  a=b 的文本比較表現爲使用 BINARY(二進制)整理序列。 */

SELECT x FROM  t1 WHERE a = b ORDER BY  x;

--結果 1 2 3

  

/*  a=b 的文本比較表現爲使用 RTRIM 整理序列。 */

SELECT x FROM  t1 WHERE a = b COLLATE RTRIM ORDER  BY x;

--結果 1 2 3 4

  

/*  d=a 的文本比較表現爲使用 NOCASE 整理序列。 */

SELECT x FROM  t1 WHERE d = a ORDER BY  x;

--結果 1 2 3 4

  

/*  a=d 的文本比較表現爲使用 BINARY(二進制)整理序列。 */

SELECT x FROM  t1 WHERE a = d ORDER BY  x;

--結果 1 4

  

/* 'abc'=c 的文本比較表現爲使用 RTRIM (二進制)整理序列。 */

SELECT x FROM  t1 WHERE 'abc'  = c ORDER BY x;

--結果 1 2 3

  

/* c='abc' 的文本比較表現爲使用 RTRIM 整理序列。 */

SELECT x FROM  t1 WHERE c = 'abc' ORDER  BY x;

--結果 1 2 3

  

/* 分組表現爲使用 NOCASE 整理序列(值'abc''ABC' 'Abc'

** 被分爲同一組)。*/

SELECT count(*)  FROM t1 GROUP  BY d ORDER  BY 1;

--結果 4

  

/* 分組表現爲使用 BINARY整理序列(值'abc''ABC' 'Abc'

** 被分爲不同的組)。*/

SELECT count(*)  FROM t1 GROUP  BY (d || '')  ORDER BY  1;

--結果 1 1 2

  

/* c排序表現爲使用 RTRIM 整理序列。*/(譯註:sorting or column  c 疑爲 sorting of...誤寫)

SELECT x FROM  t1 ORDER BY c, x;

--結果 4 1 2 3

  

/*  (c||'')排序表現爲使用 BINARY整理序列。*/

SELECT x FROM  t1 ORDER BY (c||''), x;

--結果 4 2 3 1

  

/* c排序表現爲使用 NOCASE 整理序列。*/

SELECT x FROM  t1 ORDER BY c COLLATE  NOCASE, x;

--結果 2 4 3 1

 

 


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