小巧、快速、可靠
任選三項
建立資料表

1. 語法

create-table-stmt

CREATE TEMP TEMPORARY TABLE IF NOT EXISTS schema-name . table-name ( column-def table-constraint , ) table-options , AS select-stmt

column-def

select-stmt

table-constraint

table-options

2. CREATE TABLE 指令

「CREATE TABLE」指令用於在 SQLite 資料庫中建立新資料表。CREATE TABLE 指令會指定新資料表的下列屬性

每個 CREATE TABLE 陳述式都必須指定新表格的名稱。以「sqlite_」開頭的表格名稱保留供內部使用。嘗試建立一個名稱以「sqlite_」開頭的表格會產生錯誤。

如果指定了 schema-name,它必須是「main」、「temp」或 附加資料庫 的名稱。在此情況下,新表格會建立在指定的資料庫中。如果「CREATE」和「TABLE」之間出現「TEMP」或「TEMPORARY」關鍵字,則新表格會建立在臨時資料庫中。除非 schema-name 為「temp」,否則同時指定 schema-name 和 TEMP 或 TEMPORARY 關鍵字會產生錯誤。如果未指定 schema 名稱且不存在 TEMP 關鍵字,則會在主資料庫中建立表格。

嘗試在已包含同名表格、索引或檢視的資料庫中建立新表格通常會產生錯誤。但是,如果在 CREATE TABLE 陳述式中指定「IF NOT EXISTS」子句,且已存在同名表格或檢視,則 CREATE TABLE 指令只會沒有作用(且不會傳回錯誤訊息)。如果無法建立表格,因為有現有的索引,即使指定了「IF NOT EXISTS」子句,仍然會傳回錯誤。

建立一個與現有 觸發器 同名的表格並非錯誤。

使用 DROP TABLE 陳述式移除表格。

2.1. CREATE TABLE ... AS SELECT 陳述

「CREATE TABLE ... AS SELECT」陳述會根據 SELECT 陳述的結果建立並填入資料庫表格。表格的欄位數目與 SELECT 陳述回傳的數目相同。每個欄位的名稱與 SELECT 陳述的結果集中對應欄位的名稱相同。每個欄位的宣告類型由 SELECT 陳述的結果集中對應表達式的表達式親和性決定,如下所示

表達式親和性 欄位宣告類型
TEXT "TEXT"
NUMERIC "NUM"
INTEGER "INT"
REAL "REAL"
BLOB(又稱「NONE」) ""(空字串)

使用 CREATE TABLE AS 建立的表格沒有 PRIMARY KEY 且沒有任何類型的約束。每個欄位的預設值為 NULL。新表格中每個欄位的預設排序順序為 BINARY。

使用 CREATE TABLE AS 建立的表格最初會填入 SELECT 陳述回傳的資料列。列會連續指派遞增的rowid值,從 1 開始,依據 SELECT 陳述回傳的順序指派。

3. 欄位定義

除非是 CREATE TABLE ... AS SELECT 語句,CREATE TABLE 包含一個或多個 欄位定義,選擇性地接著 資料表約束 清單。每個欄位定義包含欄位名稱,選擇性地接著欄位的宣告類型,然後是一個或多個選擇性的 欄位約束。在先前語句的目的中,包含在「欄位約束」定義中的是 COLLATE 和 DEFAULT 子句,即使它們在實際上並非約束,因為它們並未限制資料表可能包含的資料。其他約束 - NOT NULL、CHECK、UNIQUE、PRIMARY KEY 和 FOREIGN KEY 約束 - 對資料表資料施加限制。

資料表中的欄位數量受 SQLITE_MAX_COLUMN 編譯時期參數限制。資料表中的單一列無法儲存超過 SQLITE_MAX_LENGTH 位元組的資料。這兩個限制都可以在執行階段使用 sqlite3_limit() C/C++ 介面降低。

3.1. 欄位資料類型

與大多數 SQL 資料庫不同,SQLite 根據欄位宣告的類型,不限制可以插入欄位中的資料類型。相反地,SQLite 使用 動態型別。欄位的宣告類型僅用於決定欄位的 關聯性

3.2. DEFAULT 子句

DEFAULT 子句指定當使用者在執行 INSERT 時,未明確提供欄位值時,要使用的預設值。如果欄位定義中沒有附加明確的 DEFAULT 子句,則欄位的預設值為 NULL。明確的 DEFAULT 子句可以指定預設值為 NULL、字串常數、blob 常數、有號數字或括號中包含的任何常數運算式。預設值也可以是下列不分大小寫的特殊關鍵字之一:CURRENT_TIME、CURRENT_DATE 或 CURRENT_TIMESTAMP。就 DEFAULT 子句而言,如果運算式不包含子查詢、欄位或資料表參照、繫結參數或使用雙引號(而非單引號)括起來的字串文字,則該運算式會被視為常數。

每次透過 INSERT 陳述式將列插入資料表中,而該陳述式未提供所有資料表欄位的明確值時,新列中儲存的值會根據其預設值決定,如下所示:

3.3. COLLATE 子句

COLLATE 子句指定要作為欄位預設排序規則的 排序規則 名稱。如果未指定 COLLATE 子句,則預設排序規則為 BINARY

3.4. GENERATED ALWAYS AS 子句

包含 GENERATED ALWAYS AS 子句的欄位是 產生式欄位。產生式欄位從 SQLite 版本 3.31.0 (2020-01-22) 開始支援。請參閱 個別文件,以深入了解產生式欄位的功能和限制。

3.5. 主鍵

SQLite 中的每個表格最多可以有一個主鍵。如果將主鍵關鍵字新增到欄位定義中,則表格的主鍵就由該單一欄位組成。或者,如果將主鍵子句指定為 表格約束,則表格的主鍵就由主鍵子句中指定的一系列欄位組成。主鍵子句只能包含欄位名稱,不支援在主鍵的 索引欄位 中使用運算式。如果在 CREATE TABLE 陳述式中出現多個主鍵子句,則會產生錯誤。主鍵對於一般表格是選用的,但對於 WITHOUT ROWID 表格則是必要的。

如果表格有單一欄位主鍵,且該欄位的宣告類型為「INTEGER」,而表格不是 WITHOUT ROWID 表格,則該欄位稱為 INTEGER 主鍵。請參閱 以下 的說明,以了解與 INTEGER 主鍵 相關的特殊屬性和行為。

在具有主鍵的表格中,每一列都必須在主鍵欄位中具有獨一無二的值組合。在決定主鍵值唯一性的目的上,NULL 值被視為與所有其他值不同,包含其他 NULL 值。如果 INSERTUPDATE 陳述嘗試修改表格內容,讓兩列或更多列具有相同的主鍵值,那將會違反約束。

根據 SQL 標準,PRIMARY KEY 應該總是暗示 NOT NULL。遺憾的是,由於某些早期版本的錯誤,SQLite 中並非如此。除非該欄位是 INTEGER PRIMARY KEY 或表格是 WITHOUT ROWID 表格或 STRICT 表格,或欄位宣告為 NOT NULL,SQLite 允許在 PRIMARY KEY 欄位中使用 NULL 值。SQLite 可以修正為符合標準,但這麼做可能會破壞舊有應用程式。因此,決定僅記錄 SQLite 在大多數 PRIMARY KEY 欄位中允許 NULL 的事實。

3.6. UNIQUE 約束

UNIQUE 約束類似於 PRIMARY KEY 約束,不同的是單一表格可以有任意數量的 UNIQUE 約束。對於表格上的每個 UNIQUE 約束,每一列都必須在 UNIQUE 約束所識別的欄位中包含獨一無二的值組合。在 UNIQUE 約束的目的上,NULL 值被視為與所有其他值不同,包含其他 NULL 值。與 PRIMARY KEY 一樣,UNIQUE table-constraint 子句只能包含欄位名稱 — 在 UNIQUE table-constraintindexed-column 中使用表達式不受支援。

在多數情況下,UNIQUE 和 PRIMARY KEY 約束會透過在資料庫中建立唯一索引來實作。(例外是 INTEGER PRIMARY KEYWITHOUT ROWID 表格上的 PRIMARY KEY。)因此,下列架構在邏輯上是等效的

  1. 建立資料表 t1(a, b UNIQUE);

  2. 建立資料表 t1(a, b PRIMARY KEY);

  3. 建立資料表 t1(a, b);
    在 t1(b) 建立唯一索引 t1b;

3.7. 檢查約束

檢查約束可以附加到欄位定義或指定為資料表約束。實際上沒有差別。每次將新資料列插入資料表或更新現有資料列時,會評估與每個檢查約束關聯的表達式,並以與 CAST 表達式 相同的方式轉換為 NUMERIC 值。如果結果為零(整數值 0 或實數值 0.0),則表示發生約束違規。如果檢查表達式評估為 NULL 或任何其他非零值,則不構成約束違規。檢查約束的表達式不得包含子查詢。

只有在寫入資料表時才會驗證檢查約束,不會在讀取時驗證。此外,可以使用 "PRAGMA ignore_check_constraints=ON;" 陳述式暫時停用檢查約束的驗證。因此,查詢可能會產生違反檢查約束的結果。

3.8. NOT NULL 約束

NOT NULL 約束只能附加到欄位定義,不能指定為資料表約束。不出所料,NOT NULL 約束規定關聯欄位不得包含 NULL 值。在插入新資料列或更新現有資料列時嘗試將欄位值設定為 NULL 會導致約束違規。查詢期間不會驗證 NOT NULL 約束,因此即使欄位標記為 NOT NULL,如果資料庫檔案已損毀,欄位的查詢可能會產生 NULL 值。

4. 約束強制執行

約束會在 INSERTUPDATE 期間以及 PRAGMA integrity_checkPRAGMA quick_check 以及有時在 ALTER TABLE 期間進行檢查。查詢和 DELETE 陳述式通常不會驗證約束。因此,如果資料庫檔案已損毀(可能是因為外部程式直接變更資料庫檔案,而未透過 SQLite 函式庫),查詢可能會傳回違反約束的資料。例如

CREATE TABLE t1(x INT CHECK( x>3 ));
/* Insert a row with X less than 3 by directly writing into the
** database file using an external program */
PRAGMA integrity_check;  -- Reports row with x less than 3 as corrupt
INSERT INTO t1(x) VALUES(2);  -- Fails with SQLITE_CORRUPT
SELECT x FROM t1;  -- Returns an integer less than 3 in spite of the CHECK constraint

使用 PRAGMA ignore_check_constraints=ON; 陳述式,可以暫時停用 CHECK 約束的執行。

4.1. 對約束違規的回應

對約束違規的回應是由 約束衝突解決演算法 決定。每個 PRIMARY KEY、UNIQUE、NOT NULL 和 CHECK 約束都有預設的衝突解決演算法。PRIMARY KEY、UNIQUE 和 NOT NULL 約束可以透過在定義中包含 衝突條款,明確指定其他預設衝突解決演算法。或者,如果約束定義不包含 衝突條款,預設的衝突解決演算法就是 ABORT。CHECK 約束的衝突解決演算法永遠都是 ABORT。(僅為了歷史相容性,表格 CHECK 約束允許有衝突解決條款,但沒有效果。)同一個表格中的不同約束可能有不同的預設衝突解決演算法。請參閱標題為 ON CONFLICT 的區段,以取得更多資訊。

5. ROWID 和 INTEGER PRIMARY KEY

除了 WITHOUT ROWID 表格之外,SQLite 表格中的所有列都有 64 位元的簽署整數鍵,可在其表格中唯一識別該列。這個整數通常稱為「rowid」。可以使用特殊的不分大小寫名稱「rowid」、「oid」或「_rowid_」,取代欄位名稱來存取 rowid 值。如果表格包含名為「rowid」、「oid」或「_rowid_」的使用者定義欄位,則該名稱永遠是指明確宣告的欄位,而且無法用來擷取整數 rowid 值。

WITHOUT ROWID 表格中,會省略 rowid(以及「oid」和「_rowid_」)。WITHOUT ROWID 表格僅在 SQLite 版本 3.8.2(2013-12-06)及更新版本中提供。缺少 WITHOUT ROWID 子句的表格稱為「rowid 表格」。

rowid 表格的資料儲存在 B 樹狀結構中,每個表格列包含一則記錄,並使用 rowid 值作為金鑰。這表示透過 rowid 擷取或排序記錄的速度很快。搜尋具有特定 rowid 的記錄,或搜尋 rowid 在指定範圍內的記錄,速度約為透過指定任何其他 PRIMARY KEY 或索引值進行類似搜尋的兩倍。

除了以下所述的例外情況外,如果 rowid 表格具有由單一欄位組成的主鍵,且該欄位的宣告類型為任何大小寫組合的「INTEGER」,則該欄位會成為 rowid 的別名。此類欄位通常稱為「整數主鍵」。PRIMARY KEY 欄位僅在宣告類型名稱完全為「INTEGER」時才會成為整數主鍵。其他整數類型名稱,例如「INT」、「BIGINT」、「SHORT INTEGER」或「UNSIGNED INTEGER」,會導致主鍵欄位表現得如同具有整數 相似性 和唯一索引的普通表格欄位,而不是 rowid 的別名。

上述例外情況是,如果宣告類型為「INTEGER」的欄位宣告包含「PRIMARY KEY DESC」子句,則它不會成為 rowid 的別名,也不會被分類為整數主鍵。這種怪異現象並非設計使然,而是 SQLite 早期版本中的錯誤所致。但修正錯誤可能會導致向後不相容。因此,已保留(並記錄)原始行為,因為在特定情況下的異常行為遠比相容性中斷好。這表示以下三個表格宣告都會導致欄位「x」成為 rowid(整數主鍵)的別名

但下列宣告不會導致「x」成為 rowid 的別名

Rowid 值可以用 UPDATE 陳述式修改,就像修改任何其他欄位值一樣,可以使用內建別名(「rowid」、「oid」或「_rowid_」)或使用整數主鍵建立的別名。同樣地,INSERT 陳述式可以提供一個值,用作每一列插入的 rowid。與一般的 SQLite 欄位不同,整數主鍵或 rowid 欄位必須包含整數值。整數主鍵或 rowid 欄位無法儲存浮點值、字串、BLOB 或 NULL。

如果 UPDATE 陳述式嘗試將整數主鍵或 rowid 欄位設定為 NULL 或 blob 值,或設定為無法無損失轉換為整數的字串或實數值,就會發生「資料類型不符」錯誤,且陳述式會中止。如果 INSERT 陳述式嘗試將 blob 值,或無法無損失轉換為整數的字串或實數值插入整數主鍵或 rowid 欄位,就會發生「資料類型不符」錯誤,且陳述式會中止。

如果 INSERT 陳述式嘗試將 NULL 值插入 rowid 或整數主鍵欄位,系統會自動選擇一個整數值用作 rowid。如何執行此動作的詳細說明已另外提供。

一個父鍵外來鍵約束不允許使用 rowid。父鍵只能使用命名欄位。

此頁面最後修改於 2024-03-13 17:43:35 UTC