數據庫 - SQLite3 中的數據類型

------------------------------

安裝 Sqlite3 和 數據庫查看工具:

sudo apt-get install sqlite3
sudo apt-get install sqlitebrowser

------------------------------

基礎概念:

  數據表中,縱向的一整列叫「列」,橫向的一整行叫「記錄」,「記錄」中每一格叫「字段」,字段的內容叫「數據」

------------------------------

SQL 建立數據表:

Create Table 表名稱 { 列名稱 列數據類型, 列名稱 列數據類型, ... };

  首先要知道,大多數的數據庫引擎都使用「靜態數據類型」(基本上除了 SQLite 以外的全部 SQL 數據庫引擎都使用「靜態數據類型」),使用靜態類型,數據的類型就由它的「列」決定,與「列」類型不相符的數據是沒法寫入到該「列」中的。

  而 SQLite 採用的是「動態數據類型」(能夠理解爲 SQLite 是「無類型限制」的),這意味着你能夠保存任何類型的「數據」到任何「表」的任何「列」中(整形主鍵「列」除外),不管這「列」聲明的數據類型是什麼。對於 SQLite 來講,不指定「數據類型」是徹底合法的。如:

Create Table 表名稱 { 列名稱, 列名稱, ... };

  儘管 SQLite 爲咱們提供了這種方便,可是考慮到數據庫的平臺可移植性,咱們在實際的開發中仍是應該聲明「數據類型」,而且保證「存入的數據類型」和「聲明的數據類型」是一致的。除非你有極爲充分的理由,同時再也不考慮數據庫平臺的移植問題,在此種狀況下確實可使用 SQLite 提供的這一特性。

------------------------------

  雖然 SQLite 對「數據類型」沒有強制要求,但 SQLite 定義了 5 種最基本的「存儲類型」,它們決定了「數據」在數據庫中的存在形式。每一個存放在 SQLite 數據庫中的值(或者由這個數據庫引擎操做的值)都屬於下面 5 種「存儲類型」中的一種:

1   NULL    無值(什麼也沒有,不等同於「空字符串」或 0)
2   INTEGER 有符號整數(根據值的大小存儲在 一、二、三、四、六、8 字節中)
3   REAL    浮點數(8 字節的 IEEE 浮點數字)
4   TEXT    字符串(使用數據庫內部的編碼方式存儲,默認 UTF-8)
5   BLOB    字節流(原樣存儲)

  也就是說 SQLite 本質上只有 5 種類別的數據,在 SQLite 的數據庫中,也只能存入這 5 種類別的數據。

  INTEGER 「存儲類型」包含 6 種不一樣長度的不一樣整形的「數據類型」,這隻在磁盤上形成了差別。當 INTEGER 值被從磁盤中讀入到內存中之後,它們均被轉換成最通常的數據類型(8 字節有符號整形)。

  SQLite 的 TEXT 編碼方式能夠經過 SQL 語句 PRAGMA encoding 來查詢和修改:

// 查詢當前編碼方式,默認 UTF-8
PRAGMA encoding;

// 設置當前編碼方式,只有如下幾種
PRAGMA encoding = "UTF-8";
PRAGMA encoding = "UTF-16";
PRAGMA encoding = "UTF-16le";
PRAGMA encoding = "UTF-16be";

------------------------------

  雖然 SQLite 對「數據類型」沒有強制要求,但依然有本身的「數據類型」,SQLite 內定了 5 種最基本的「數據類型」,它們決定了「數據」在寫入數據庫時的「修正方式」。全部的非內定「數據類型」最終都會被視爲相應的內定「數據類型」。下面列出了 5 種內定的數據類型:

一、INTEGER

  當「文本類型」的數據被插入到此類字段中時,會被自動轉換爲 INTEGER 格式(前提是轉換操做不會致使數據信息丟失以及徹底可逆),以後再插入到目標字段中。若是轉換失敗,則 SQLite 仍會以 TEXT 方式存儲該數據。

  對於 NULL 或 BLOB 類型的數據,SQLite 將不作任何轉換,直接以 NULL 或 BLOB 的方式存儲該數據。

  須要額外說明的是,對於浮點格式的「常量文本」,如 '30000.0',若是該值能夠轉換爲 INTEGER 類型,同時又不會丟失數值信息,那麼 SQLite 就會將其轉換爲 INTEGER 格式 3000 進行存儲。

二、REAL

  規則等同於 INTEGER 數據類型,「文本類型」的數據會被轉換爲 REAL 格式。

三、NUMERIC

  規則等同於 INTEGER 數據類型,「文本類型」的數據會被轉換爲 INTEGER 或 REAL 格式,優先轉換爲 INTEGER 格式,若是不能轉換爲 INTEGER 格式,再嘗試轉換爲 REAL 格式。

  在執行 CAST 表達式時與 INTEGER 有差異。

四、TEXT

  當「數值類型」的數據被插入到此類字段中時,會被自動轉換爲 TEXT 格式,以後再插入到目標字段中。

五、BLOB

  當「任何類型」的數據被插入到此類字段中時,將不作任何的轉換,直接以該數據所屬的數據類型進行存儲。

------------------------------

  雖然 SQLite 有本身內定的「數據類型」,但依然可使用非內定的「數據類型」來定義「列」。事實上,SQLite 接受「任意字符串」做爲「數據類型」使用,也就是說,你可使用「ABC」、「HELLO」等做爲「數據類型」來定義「列」,若是你以爲這樣作有意義的話。

  最終,SQLite 會把非內定的「數據類型」歸類爲某一個內定的「數據類型」,並將其視爲內定「數據類型」來使用。歸類原則以下:

一、若是「數據類型」字符串中包含「INT」,那麼這些「數據類型」被歸類爲 INTEGER 類型。

二、若是「數據類型」字符串中包含「CHAR」、「CLOB」或「TEXT」,那麼這些「數據類型」被歸類爲 TEXT 類型。

三、若是「數據類型」字符串中包含「BLOB」,那麼這些「數據類型」被歸類爲 BLOB 類型。

四、若是「數據類型」字符串中包含「REAL」、「FLOA」或「DOUB」,那麼這些「數據類型」被歸類爲 REAL 類型。

五、其他的「數據類型」被歸類爲 NUMERIC 類型。

  這 5 條歸類原則具備前後優先級,前面的規則優先於後面的規則,好比某「列」的「數據類型」聲明爲「CharInt」,既有第 2 條規則中的「Char」,又有第 1 條規則中的「Int」,那麼根據前後順序,應該優先遵循第 1 條規則,則「CharInt」會被視爲 INTEGER 類型。

  在 SQLite 中,類型 CHAR(255) 的長度信息 255 沒有任何實際意義,僅僅是爲了與其它數據庫平臺的聲明保持一致性,CHAR(255) 最終會以 TEXT 格式存入數據庫,沒有長度限制。

----------

舉例說明:

  好比聲明某「列」的「數據類型」是「CHAR(255)「,根據「類型歸類原則」,該「列」被視爲 TEXT 類型,若是存入的數據是數值 32,那麼在存入以前,SQLite 會把 32 轉換爲字符串 '32' 再存入相應的字段中。

  若是聲明的「數據類型」是「SMALLINT」,根據「類型歸類原則」,該「列」被視爲 INTEGER 類型,若是存入的數據是字符串 '-32.0',那麼在存入以前,SQLite 會把 '-32.0' 轉換爲整數 -32 再存入相應的字段中。可是,若是存入的是 'A32' 或 '-32.5',則沒法正確轉換,此時 SQLite 會以 TEXT 的形式將 'A32' 或 '-32.5' 存入相應的字段中。

  若是聲明的「數據類型」是「ABC」,根據「類型歸類原則」,該「列」被視爲 NUMERIC 類型,若是存入的數據是字符串 '-32.0',那麼在存入以前,SQLite 會把 '-32.0' 轉換爲整數 -32 再存入相應的字段中。若是存入的是 '-32.5',則 SQLite 會把 '-32.5' 轉換爲浮點數 -32.5 再存入相應的字段中。若是存入的是 'A32',則 SQLite 會以 TEXT 的形式將 'A32' 存入相應的字段中。

------------------------------

關於布爾值的存儲:

  SQLite 沒有單獨的「布爾存儲類型」,它使用 INTEGER 類型來存儲布爾值,0 爲 false,1 爲 true。通常的作法是將布爾值轉換爲 0 或 1,而後再寫入 SQLite 數據庫中。

  下面的 Golang 代碼會自動將 true 和 false 轉換爲 1 和 0:

sql.DB.Exec("insert into data values (?,?)", true,false)

  不能直接在 SQL 語句中使用 true 或 false,好比下面的代碼將沒法執行成功:

sql.DB.Exec("insert into data values (true,false)")

------------------------------

關於日期時間的存儲:

  SQLite 沒有提供專門的「日期時間存儲類型」,若是要存儲日期時間,必須先將日期時間轉換成 SQLite 內定的「數據類型」,而後再寫入數據庫。

  SQLite 內置的日期和時間函數(date、time、datetime、julianday、strftime)可以將「日期時間字符串」轉換爲 TEXT,REAL 或 INTEGER 形式存放,程序能夠任意選擇這幾個「存儲類型」去存儲日期和時間:

  TEXT    做爲 IS08601 字符串("YYYY-MM-DD HH:MM:SS.SSS")
  REAL    從格林威治時間 11 月 24 日,4174 B.C 中午以來的天數
  INTEGER 從 1970-01-01 00:00:00 UTC 以來的秒數

------------------------------

關於比較表達式:

  在 SQLite3 中支持的「比較表達式」有:=、==、<、<=、>、>=、!=、<>、IN、NOT IN、BETWEEN、IS、IS NOT。

  數據的比較結果主要依賴於操做數的存儲方式,其規則爲:

一、存儲方式爲 NULL 的數值小於其它存儲類型的值。

二、存儲方式爲 INTEGER 和 REAL 的數值小於 TEXT 或 BLOB 類型的值,若是同爲INTEGER 或 REAL,則基於數值規則進行比較。

三、存儲方式爲 TEXT 的數值小於 BLOB 類型的值,若是同爲 TEXT,則基於文本規則(ASCII 值)進行比較。

四、若是是兩個 BLOB 類型的數值進行比較,其結果爲 C 運行時函數 memcmp() 的結果。

  即:NULL < INTEGER、REAL < TEXT < BLOB

------------------------------

關於數學操做符:

  全部的「數學操做符」(+、-、*、/、%、<<、>>、&、、|)在執行數學運算前都會先將「操做數」轉換爲 NUMERIC 存儲類型,即便在轉換過程當中可能會形成數據信息的丟失。此外,若是其中一個操做數爲 NULL,那麼它們的運算結果亦爲 NULL。在數學操做符中,若是其中一個操做數看上去並不像數值類型,那麼它們的運算結果爲 0 或 0.0。

------------------------------

總結:

  在使用 Create Table 表名稱 { 列名稱 列數據類型, 列名稱 列數據類型, ... }; 建立 SQLite 數據表時,「列數據類型」最好選用 INTEGER、REAL、NUMERIC、TEXT、BLOB 其中之一,由於 SQLite 本質上只支持這些「數據類型」。若是要兼容其它數據庫平臺,那麼最好選用其它數據庫平臺支持的「數據類型」做爲「列數據類型」。

  在向數據庫中寫入數據時,要保證「寫入的數據類型」與「聲明的數據類型」一致,這樣建立出來的數據庫文件才能兼容其它數據庫平臺。



相關文章
相關標籤/搜索