SQLite 致力於彈性處理其儲存內容的資料類型。例如,如果表格欄位類型為「INTEGER」,SQLite 會嘗試將插入該欄位的任何內容轉換為整數。因此,嘗試插入字串「123」會導致插入整數 123。但如果內容無法無損失地轉換為整數,例如輸入為「xyz」,則會插入原始字串。請參閱 SQLite 中的資料類型 文件以取得更多資訊。
有些開發人員 欣賞 SQLite 的彈性輸入規則提供的自由,並善用此自由。但其他開發人員對 SQLite 肆無忌憚地違反規則感到震驚,並偏好所有其他 SQL 資料庫引擎和 SQL 標準中發現的傳統嚴格類型系統。對於後者,SQLite 支援嚴格輸入模式,自版本 3.37.0 (2021-11-27) 起,可為每個表格個別啟用。
在 CREATE TABLE 陳述式中,如果在結尾處的「)」之後加入「STRICT」表格選項關鍵字,則會將嚴格輸入規則套用於該表格。STRICT 關鍵字會造成以下差異
每個欄位定義都必須為該欄位指定資料類型。無法再指定沒有資料類型的欄位。
資料類型必須為下列其中一種
不允許任何其他資料類型名稱,儘管在未來版本的 SQLite 中可能會新增新的類型。
插入到資料類型不是 ANY 的欄位中的內容必須是 NULL(假設欄位沒有 NOT NULL 的限制)或指定的資料類型。SQLite 會嘗試使用一般的相似性規則將資料轉換成適當的資料類型,就像 PostgreSQL、MySQL、SQL Server 和 Oracle 所做的一樣。如果無法在指定的資料類型中無損失地轉換值,則會引發 SQLITE_CONSTRAINT_DATATYPE 錯誤。
資料類型為 ANY 的欄位可以接受任何種類的資料(當然,如果它們有 NOT NULL 的限制,它們會拒絕 NULL 值)。在 STRICT 表格中,ANY 類型的欄位不會發生類型轉換。
作為 PRIMARY KEY 一部分的欄位隱含 NOT NULL。然而,即使 PRIMARY KEY 有隱含的 NOT NULL 限制,當 NULL 值插入到 INTEGER PRIMARY KEY 欄位時,NULL 會自動轉換成唯一的整數,使用與一般非嚴格表格上的 INTEGER PRIMARY KEY 相同的規則。
PRAGMA integrity_check 和 PRAGMA quick_check 命令會檢查 STRICT 表格中所有欄位內容的類型,並在有任何問題時顯示錯誤。
STRICT 表格的其他所有內容都與一般非嚴格表格中的運作方式相同
多年來,在單一欄位中儲存任何類型資料的能力已證明非常有用。為了繼續支援此能力,即使在 STRICT 表格中,也引入了新的 ANY 資料類型名稱。當欄位的資料類型為「ANY」時,表示任何類型的資料(整數、浮點值、字串或二進位大型物件)都可以插入該表格中,且其值和資料類型會完全按照插入的方式保留。據我們所知,SQLite 是唯一支援此進階功能的 SQL 資料庫引擎。
ANY 的行為在 STRICT 表格中與一般非嚴格表格中略有不同。在 STRICT 表格中,類型為 ANY 的欄位會永遠完全按照接收到的方式保留資料。對於一般非嚴格表格,類型為 ANY 的欄位會嘗試將看起來像數字的字串轉換為數字值,如果成功,會儲存數字值而非原始字串。例如
STRICT | 一般非嚴格 |
---|---|
CREATE TABLE t1(a ANY) STRICT; INSERT INTO t1 VALUES('000123'); SELECT typeof(a), quote(a) FROM t1; -- result: text '000123' | CREATE TABLE t1(a ANY); INSERT INTO t1 VALUES('000123'); SELECT typeof(a), quote(a) FROM t1; -- result: integer 123 |
CREATE TABLE 敘述句尾端的 STRICT 關鍵字僅由 SQLite 版本 3.37.0 (2021-11-27) 及後續版本辨識。如果您嘗試在較早版本的 SQLite 中開啟包含 STRICT 關鍵字的資料庫,它將無法辨識該關鍵字,並回報錯誤(除非如下所述)。但除了額外的 STRICT 關鍵字外,資料庫的底層檔案格式是相同的。
因此,一般而言,包含一個或多個 STRICT 資料表的資料庫檔案只能由 SQLite 版本 3.37.0 或後續版本讀取和寫入。不過,由 SQLite 3.37.0 或後續版本建立的資料庫仍可由較早版本的 SQLite 讀取和寫入,只要資料庫不包含任何 STRICT 資料表或其他在較舊版本的 SQLite 之後才導入的功能,最早可回溯至版本 3.0.0 (2004-06-18)。
STRICT 關鍵字仍可用作識別碼。(它僅在語法的特定部分被視為關鍵字,而 sqlite3_keyword_check(..) 不會將它辨識為一般關鍵字。)
由於 SQL 語言剖析器的奇特行為,早於 3.37.0 的 SQLite 版本仍可在開啟資料庫檔案後立即設定「PRAGMA writable_schema=ON」,在執行任何其他需要知道結構的事項之前,讀取和寫入 STRICT 資料表。PRAGMA writable_schema=ON 的其中一項功能是停用結構剖析器中的錯誤。這是故意的,因為 PRAGMA writable_schema=ON 的一大原因是為了協助復原結構損毀的資料庫檔案。因此,當結構剖析器在 writable_schema=ON 時遇到 STRICT 關鍵字,它會告訴自己「我不知道如何處理這個,但到目前為止一切都像有效的資料表定義,所以我只會使用我有的東西。」因此,STRICT 關鍵字實際上被忽略了。由於 STRICT 資料表的檔案格式並未有其他變更,所有其他部分都會正常運作。當然,嚴格類型強制不會發生,因為較早版本的 SQLite 不知道如何執行此操作。
CLI 中的 .dump 指令會設定 PRAGMA writable_schema=ON,因為 .dump 的設計目的是從損毀的資料庫檔案中萃取盡可能多的內容。因此,如果您使用的是舊版的 SQLite,而且您在 CLI 中開啟一個包含 STRICT 表格的資料庫,並在執行其他任何動作之前發出「.dump」指令,您將能夠在不進行嚴格類型強制的情況下讀取和寫入 STRICT 表格。這可能會損毀資料庫,因為它允許不正確的類型進入 STRICT 表格。使用較新版本的 SQLite 重新開啟資料庫並執行「PRAGMA quick_check」將會偵測並報告所有此類損毀。
SQLite 剖析器會接受在 CREATE TABLE 陳述式中最後一個閉合括號之後的逗號分隔表格選項清單。截至撰寫本文時 (2021-08-23),僅識別兩個選項
如果有多個選項,它們可以按任何順序指定。為了簡化,目前的剖析器會接受重複的選項而不抱怨,但這可能會在未來的版本中變更,因此應用程式不應依賴它。