資料定義陳述式會用來建立、修改和移除資料庫物件,例如資料表、檢視、索引和觸發程序。支援的資料定義陳述式如下:
-
資料表:
-
CREATE TABLE
-
ALTER TABLE
-
DROP TABLE
-
-
-
觸發程序:
-
CREATE TRIGGERS
-
DROP TRIGGERS
CREATE TABLE
CREATE TABLE 陳述式包含關鍵字 CREATE TABLE,後面接著新資料表的名稱,之後則是 (括在括弧裡) 欄定義和條件約束的清單。資料表名稱可為識別名稱或字串。
sql-statement ::= CREATE [TEMP | TEMPORARY] TABLE [IF NOT EXISTS] [database-name.] table-name
( column-def [, column-def]* [, constraint]* )
sql-statement ::= CREATE [TEMP | TEMPORARY] TABLE [database-name.] table-name AS select-statement
column-def ::= name [type] [[CONSTRAINT name] column-constraint]*
type ::= typename | typename ( number ) | typename ( number , number )
column-constraint ::= NOT NULL [ conflict-clause ] |
PRIMARY KEY [sort-order] [ conflict-clause ] [AUTOINCREMENT] |
UNIQUE [conflict-clause] |
CHECK ( expr ) |
DEFAULT default-value |
COLLATE collation-name
constraint ::= PRIMARY KEY ( column-list ) [conflict-clause] |
UNIQUE ( column-list ) [conflict-clause] |
CHECK ( expr )
conflict-clause ::= ON CONFLICT conflict-algorithm
conflict-algorithm ::= ROLLBACK | ABORT | FAIL | IGNORE | REPLACE
default-value ::= NULL | string | number | CURRENT_TIME | CURRENT_DATE | CURRENT_TIMESTAMP
sort-order ::= ASC | DESC
collation-name ::= BINARY | NOCASE
column-list ::= column-name [, column-name]*
每個欄定義是欄名稱後面接著該欄的資料類型,再接著一或多個選擇性的欄條件約束。欄的資料類型會限制該欄中可儲存的資料內容。如果試圖在欄中儲存不同資料類型的值,執行階段將會儘可能將值轉換為適當類型,或引發錯誤。如需其它資訊,請參閱「資料類型支援」一節。
NOT NULL 欄條件約束表示該欄不能包含 NULL 值。
UNIQUE 條件約束會導致對指定的一或多個欄建立索引。這個索引必須包含唯一的索引鍵,也就是針對指定的一或多個欄,任兩列均不得包含重複值或值組合。CREATE TABLE 陳述式可以有多個 UNIQUE 條件約束,包括在欄定義中為多個欄指定一個 UNIQUE 條件約束,和 (或) 多個資料表層級的 UNIQUE 條件約束。
CHECK 條件約束會定義一個要評估的運算式,而且該運算式必須為 True,才會插入或更新列的資料。CHECK 運算式必須解析成 Boolean 值。
欄定義中的 COLLATE 子句會指定比較欄的文字項目時所使用的文字定序函數。預設狀況下會使用 BINARY 定序函數。如需有關 COLLATE 子句和定序函數的詳細資料,請參閱「COLLATE」。
DEFAULT 條件約束會指定執行 INSERT 時所用的預設值。這個值可為 NULL、字串常數或數字。預設值也可以是 CURRENT_TIME、CURRENT_DATE 或 CURRENT_TIMESTAMP 這幾個不區分大小寫的特殊關鍵字中的一個。如果值是 NULL、字串常數或數字,每當 INSERT 陳述式未針對該欄指定值時,這個值就會逐字插入欄中。如果值是 CURRENT_TIME、CURRENT_DATE 或 CURRENT_TIMESTAMP,則會將目前的 UTC 日期和 (或) 時間插入欄中。CURRENT_TIME 的格式是 HH:MM:SS。CURRENT_DATE 的格式是 YYYY-MM-DD。CURRENT_TIMESTAMP 的格式是 YYYY-MM-DD HH:MM:SS。
指定 PRIMARY KEY 通常只會在對應的欄上建立 UNIQUE 索引。但如果在具有 INTEGER 資料類型 (或其中一個同義詞,例如 int) 的單一欄上指定 PRIMARY KEY 條件約束,資料庫便會使用該欄做為資料表的實際主索引鍵。這表示該欄只能存放唯一的整數值 (請注意,在許多 SQLite 實作中,只有 INTEGER 欄類型會將欄當做內部主索引鍵使用,但是在 INTEGER 的 Adobe AIR 同義詞 (例如 int) 中,也會指定該行為)。
如果資料表沒有 INTEGER PRIMARY KEY 欄,則插入列時會自動產生整數索引鍵。只要使用 ROWID、OID 或 _ROWID_ 幾個特殊名稱的其中一個,便可以隨時存取列的主索引鍵。不論是明確宣告的 INTEGER PRIMARY KEY 或內部產生的值,都可以使用這些名稱。但是,如果資料表具有明確的 INTEGER PRIMARY KEY,結果資料中的欄名稱便是實際的欄名稱,而不是特殊名稱。
INTEGER PRIMARY KEY 欄也可以包含關鍵字 AUTOINCREMENT。使用AUTOINCREMENT 關鍵字時,資料庫會在執行沒有明確指定欄值的 INSERT 陳述式時,自動在 INTEGER PRIMARY KEY 欄中產生並插入循序遞增的整數索引鍵。
CREATE TABLE 陳述式中只能有一個 PRIMARY KEY 條件約束。它可以是一個欄定義的一部分,也可以是一個單一資料表層級 PRIMARY KEY 條件約束。主索引鍵欄是隱含的 NOT NULL。
接在許多條件約束後面的選擇性 conflict-clause,可以為該條件約束指定另一個預設的條件約束衝突解決演算法。預設值為 ABORT。同一個資料表中的不同條件約束可以使用不同的預設衝突解決演算法。如果 INSERT 或 UPDATE 陳述式指定不同的衝突解決演算法,就會使用該演算法取代 CREATE TABLE 陳述式中指定的演算法。如需詳細資訊,請參閱
特殊陳述式和子句
的「ON CONFLICT (衝突演算法)」小節。
額外的條件約束 (如 FOREIGN KEY 條件約束) 不會造成錯誤,但執行階段會予以忽略。
如果 CREATE 和 TABLE 之間出現 TEMP 或 TEMPORARY 關鍵字,則所建立的資料表只會顯示在同一個資料庫連線 (SQLConnection 實體) 中。關閉資料庫連線時,就會自動刪除該資料表。在暫存資料表上建立的任何索引也都是暫時性的。暫存資料表和索引儲存在與主要資料庫檔案不同的另一個檔案中。
如果指定選擇性的 database-name 前置詞,就會在具名資料庫 (以指定的資料庫名稱呼叫 attach() 方法而連接到 SQLConnection 實體的資料庫) 中建立該資料表。除非 database-name 前置詞是 temp,否則,同時指定 database-name 前置詞和 TEMP 關鍵字是錯誤的。如果未指定資料庫名稱,而且沒有 TEMP 關鍵字,則會在主要資料庫 (使用 open() 或 openAsync() 方法連接到 SQLConnection 實體的資料庫) 中建立該資料表。
欄數或資料表的條件約束數目可隨意自訂且沒有限制,另外,列中的資料數量也可隨意自訂且沒有限制。
CREATE TABLE AS 形式會以查詢結果集的形式定義資料表。資料表欄的名稱是結果中欄的名稱。
如果使用選擇性的 IF NOT EXISTS 子句,而且已經有同名的其它資料表,則資料庫會忽略 CREATE TABLE 命令。
使用 DROP TABLE 陳述式可以移除資料表,而使用 ALTER TABLE 陳述式可以進行有限的變更。
ALTER TABLE
ALTER TABLE 命令可讓使用者將現有資料表重新命名或加入新欄。資料表中的欄無法移除。
sql-statement ::= ALTER TABLE [database-name.] table-name alteration
alteration ::= RENAME TO new-table-name
alteration ::= ADD [COLUMN] column-def
RENAME TO 語法會用來將以 [database-name.] table-name 識別的資料表重新命名成 new-table-name。這個命令無法用來在附加的資料庫之間移動資料表,只能重新命名相同資料庫中的資料表。
如果重新命名的資料表有觸發程序或索引,它們在重新命名後仍會附加到資料表。但如果有任何檢視定義或由觸發程序執行的陳述式參考到重新命名的資料表,它們不會自動修改為使用新資料表名稱。如果重新命名的資料表有關聯的檢視或觸發程序,您必須手動卸除並重新建立觸發程序,或使用新的資料表名稱檢視定義。
ADD [COLUMN] 語法會用來在現有資料表中加入新欄。新欄一定會附加到現有欄清單結束處。column-def 子句可以接受 CREATE TABLE 陳述式中允許的任何形式,但有下列限制:
-
欄不可以有 PRIMARY KEY 或 UNIQUE 條件約束。
-
欄不可以有 CURRENT_TIME、CURRENT_DATE 或 CURRENT_TIMESTAMP 的預設值。
-
如果指定 NOT NULL 條件約束,該欄必須有 NULL 以外的預設值。
ALTER TABLE 陳述式的執行時間不受資料表中的資料量影響。
DROP TABLE
DROP TABLE 陳述式會移除以 CREATE TABLE 陳述式加入的資料表。卸除的資料表是具有指定 table-name 的資料表。它會從資料庫和磁碟檔案中完全移除。資料表無法復原。與資料表相關聯的所有索引也都會刪除。
sql-statement ::= DROP TABLE [IF EXISTS] [database-name.] table-name
根據預設,DROP TABLE 陳述式不會使資料庫檔案變小。資料庫中的空白空間仍會保留,並供之後的 INSERT 作業使用。若要移除資料庫中的可用空間,請使用 SQLConnection.clean() 方法。如果最初建立資料庫時,將 autoClean 參數設定為 true,則會自動釋放空間。
選擇性的 IF EXISTS 子句會抑制資料庫不存在時所發生的錯誤。
CREATE INDEX
CREATE INDEX 命令包含關鍵字 CREATE INDEX,後面接著新索引的名稱、關鍵字 ON、要編製索引的先前已建立資料表名稱,和括在括弧裡的欄名稱清單 (清單中所列是資料表中要做為索引鍵值的欄名稱)。
sql-statement ::= CREATE [UNIQUE] INDEX [IF NOT EXISTS] [database-name.] index-name
ON table-name ( column-name [, column-name]* )
column-name ::= name [COLLATE collation-name] [ASC | DESC]
每個欄名稱後面可以接著 ASC 或 DESC 關鍵字以指定排序順序,但執行階段會忽略指定的排序順序。排序方式固定採用遞增順序。
每個欄名稱後面的 COLLATE 子句會定義該欄中文字值所用的定序順序。預設的定序順序是 CREATE TABLE 陳述式中為該欄定義的定序順序。如果未指定定序順序,則使用 BINARY 定序順序。如需 COLLATE 子句和定序函數的定義,請參閱「COLLATE」。
單一資料表可附加的索引數目可隨意自訂且沒有限制,一個索引中的欄數也沒有限制。
DROP INDEX
DROP INDEX 陳述式會移除使用 CREATE INDEX 陳述式所加入的索引。指定的索引會從資料庫檔案中完全移除。唯一一個復原索引的方法是重新輸入適當的 CREATE INDEX 命令。
sql-statement ::= DROP INDEX [IF EXISTS] [database-name.] index-name
根據預設,DROP INDEX 陳述式不會使資料庫檔案變小。資料庫中的空白空間仍會保留,並供之後的 INSERT 作業使用。若要移除資料庫中的可用空間,請使用 SQLConnection.clean() 方法。如果最初建立資料庫時,將 autoClean 參數設定為 true,則會自動釋放空間。
CREATE VIEW
CREATE VIEW 命令會為預先定義的 SELECT 陳述式指定名稱。然後,這個新名稱就可以用在另一個 SELECT 陳述式的 FROM 子句中,取代資料表名稱。檢視常用來簡化查詢,可將複雜 (且常用) 的資料集合併成結構,以供其它作業使用。
sql-statement ::= CREATE [TEMP | TEMPORARY] VIEW [IF NOT EXISTS] [database-name.] view-name AS select-statement
如果 CREATE 和 VIEW 之間出現 TEMP 或 TEMPORARY 關鍵字,則所建立的檢視只會顯示在開啟資料庫的 SQLConnection 實體中,而且關閉資料庫時就會自動刪除。
如果指定 [database-name],系統會在具名資料庫 (使用 attach() 方法以指定的 name 引數連接到 SQLConnection 實體的資料庫) 中建立該檢視。除非 [database-name] 是 temp,否則,同時指定 [database-name] 和 TEMP 關鍵字是錯誤的。如果未指定資料庫名稱,而且沒有 TEMP 關鍵字,則會在主要資料庫 (使用 open() 或 openAsync() 方法連接到 SQLConnection 實體的資料庫) 中建立該檢視。
檢視是唯讀的,所以 DELETE、INSERT 或 UPDATE 陳述式不能用在檢視上,除非至少定義一個相關類型 (INSTEAD OF DELETE、INSTEAD OF INSERT、INSTEAD OF UPDATE) 的觸發程序。如需為檢視建立觸發程序的詳細資訊,請參閱「CREATE TRIGGER」。
使用 DROP VIEW 陳述式可從資料庫中移除檢視。
DROP VIEW
DROP VIEW 陳述式會移除 CREATE VIEW 陳述式所建立的檢視。
sql-statement ::= DROP VIEW [IF EXISTS] view-name
指定的 view-name 是要卸除的檢視名稱。該檢視會從資料庫移除,但基礎資料表中的任何資料都不會修改。
CREATE TRIGGER
CREATE TRIGGER 陳述式會用來在資料庫結構中加入觸發程序。觸發程序是當指定的資料庫事件 (database-event) 發生時,會自動執行的資料庫作業 (trigger-action)。
sql-statement ::= CREATE [TEMP | TEMPORARY] TRIGGER [IF NOT EXISTS] [database-name.] trigger-name
[BEFORE | AFTER] database-event
ON table-name
trigger-action
sql-statement ::= CREATE [TEMP | TEMPORARY] TRIGGER [IF NOT EXISTS] [database-name.] trigger-name
INSTEAD OF database-event
ON view-name
trigger-action
database-event ::= DELETE |
INSERT |
UPDATE |
UPDATE OF column-list
trigger-action ::= [FOR EACH ROW] [WHEN expr]
BEGIN
trigger-step ;
[ trigger-step ; ]*
END
trigger-step ::= update-statement |
insert-statement |
delete-statement |
select-statement
column-list ::= column-name [, column-name]*
觸發程序是指定為每當特定資料庫資料表發生 DELETE、INSERT 或 UPDATE 時就會引發,或每當資料表的一或多個指定欄的 UPDATE 發生更新時就會引發。除非使用 TEMP 或 TEMPORARY 關鍵字,否則觸發程序是永久性的。在這種情況下,每當 SQLConnection 實體的主要資料庫連線關閉時,就會移除該觸發程序。如果未指定時間 (BEFORE 或 AFTER),觸發程序會預設為 BEFORE。
由於只支援 FOR EACH ROW 觸發程序,所以 FOR EACH ROW 文字是選擇性的。使用 FOR EACH ROW 觸發程序時,如果 WHEN 子句陳述式評估為 true,就會針對導致引發觸發程序之陳述式所插入、更新或刪除的每個資料庫列執行 trigger-step 陳述式。
如果提供 WHEN 子句,指定為觸發程序步驟的 SQL 陳述式只會針對 WHEN 子句為 True 的列執行。如果未提供 WHEN 子句,則會針對所有列執行這些 SQL 陳述式。
在觸發程序主體 (trigger-action 子句) 內,使用特殊的資料表名稱 OLD 和 NEW,可取得受影響資料表的變更前和變更後值。OLD 和 NEW 資料表的結構符合建立觸發程序之資料表的結構。OLD 資料表包含所觸發的陳述式修改或刪除的任何列,且為執行觸發陳述式作業之前的狀態。NEW 資料表句含所觸發的陳述式修改或建立的任何列,且為執行觸發陳述式作業之後的狀態。WHEN 子句和 trigger-step 陳述式都可以使用 NEW.column-name 和 OLD.column-name 形式的參考從插入、刪除或更新的列中存取值,其中 column-name 是觸發程序相關資料表中的欄名稱。能否使用 OLD 和 NEW 資料表參考需要視觸發程序處理的 database-event 類型而定:
-
INSERT – NEW 參考有效
-
UPDATE – NEW 和 OLD 參考有效
-
DELETE – OLD 參考有效
指定的時間 (BEFORE、AFTER 或 INSTEAD OF) 會決定 trigger-step 陳述式相對於插入、修改或移除相關列的執行時間。在 UPDATE 或 INSERT 陳述式的 trigger-step 中可以指定 ON CONFLICT 子句。但如果在導致引發觸發程序的陳述式中指定 ON CONFLICT 子句,則會改用該衝突處理原則。
除了資料表觸發程序外,您也可以在檢視上建立 INSTEAD OF 觸發程序。如果在檢視上定義一或多個 INSTEAD OF INSERT、INSTEAD OF DELETE 或 INSTEAD OF UPDATE 觸發程序,則在檢視上執行相關類型的陳述式 (INSERT、DELETE 或 UPDATE) 並不是錯誤。在這種情況下,在檢視上執行 INSERT、DELETE 或 UPDATE 會導致引發相關的觸發程序。因為觸發程序是 INSTEAD OF 觸發程序,所以導致引發觸發程序的陳述式不會修改檢視的基礎資料表。但是,您可以使用觸發程序對基礎資料表執行修改作業。
在具有 INTEGER PRIMARY KEY 欄的資料表上建立觸發程序時,必須記住一個重點。如果 BEFORE 觸發程序修改了某列的 INTEGER PRIMARY KEY 欄,但導致引發觸發程序的陳述式原本即將修改該列,則更新不會發生。暫時解決方法是建立具有 PRIMARY KEY 欄的資料表,而非具有 INTEGER PRIMARY KEY 欄的資料表。
使用 DROP TRIGGER 陳述式可以移除觸發程序。卸除資料表或檢視時,與該資料表或檢視相關聯的所有觸發程序也都會自動卸除。
RAISE() 函數
特殊的 SQL 函數 RAISE() 可以使用在觸發程序的 trigger-step 陳述式中。這個函數的語法如下:
raise-function ::= RAISE ( ABORT, error-message ) |
RAISE ( FAIL, error-message ) |
RAISE ( ROLLBACK, error-message ) |
RAISE ( IGNORE )
在執行觸發程序期間,如果呼叫前三種形式之一,系統會執行指定的 ON CONFLICT 處理動作 (ABORT、FAIL 或 ROLLBACK),並結束目前陳述式的執行。由於 ROLLBACK 表示陳述式執行失敗,所以執行 execute() 方法的 SQLStatement 實體會傳送 error (SQLErrorEvent.ERROR) 事件。在傳送的事件物件中,error 屬性的 SQLError 物件會將其 details 屬性設定為 RAISE() 函數中指定的 error-message。
呼叫 RAISE(IGNORE) 時,目前觸發程序的其餘部分、導致執行觸發程序的陳述式,以及原本接著會執行的任何觸發程序都會放棄。不會回復任何資料庫變更。如果導致執行觸發程序的陳述式本身是某個觸發程序的一部分,則該觸發程序程式會從下一個步驟開頭繼續執行。如需有關衝突解決演算法的詳細資訊,請參閱「ON CONFLICT (衝突演算法)」一節。
DROP TRIGGER
DROP TRIGGER 陳述式會移除 CREATE TRIGGER 陳述式所建立的觸發程序。
sql-statement ::= DROP TRIGGER [IF EXISTS] [database-name.] trigger-name
觸發程序會從資料庫中移除。請注意,與觸發程序相關的資料表卸除時,該觸發程序就會自動卸除。