衍生欄位(有時也稱為「計算欄位」)是表格中的欄位,其值是根據同一列中其他欄位的函數計算得出的。衍生欄位可以讀取,但其值不能直接寫入。更改衍生欄位值的唯一方法是修改用於計算該衍生欄位的其他欄位的值。
在語法上,衍生欄位是使用「GENERATED ALWAYS」欄位約束來指定的。例如:
CREATE TABLE t1( a INTEGER PRIMARY KEY, b INT, c TEXT, d INT GENERATED ALWAYS AS (a*abs(b)) VIRTUAL, e TEXT GENERATED ALWAYS AS (substr(c,b,b+1)) STORED );
上述語句包含三個普通欄位,「a」(主鍵)、「b」和「c」,以及兩個衍生欄位「d」和「e」。
約束開頭的「GENERATED ALWAYS」關鍵字和結尾的「VIRTUAL」或「STORED」關鍵字都是可選的。只有「AS」關鍵字和括號中的表達式是必需的。如果省略尾部的「VIRTUAL」或「STORED」關鍵字,則預設為 VIRTUAL。因此,上面的示例語句可以簡化為:
CREATE TABLE t1( a INTEGER PRIMARY KEY, b INT, c TEXT, d INT AS (a*abs(b)), e TEXT AS (substr(c,b,b+1)) STORED );
衍生欄位可以是 VIRTUAL 或 STORED。VIRTUAL 欄位的值在讀取時計算,而 STORED 欄位的值在寫入列時計算。STORED 欄位會佔用資料庫檔案中的空間,而 VIRTUAL 欄位在讀取時會使用更多 CPU 週期。
從 SQL 的角度來看,STORED 和 VIRTUAL 欄位幾乎完全相同。針對這兩類衍生欄位的查詢會產生相同的結果。唯一的函數差異是無法使用 ALTER TABLE ADD COLUMN 命令新增新的 STORED 欄位。只有 VIRTUAL 欄位可以使用 ALTER TABLE 新增。
衍生欄位可以具有資料類型。SQLite 會嘗試使用與普通欄位相同的親和性規則,將產生表達式的結果轉換為該資料類型。
衍生欄位可以像普通欄位一樣具有 NOT NULL、CHECK 和 UNIQUE 約束,以及外鍵約束。
衍生欄位可以像普通欄位一樣參與索引。
衍生欄位的表達式可以參考表格中任何其他已宣告的欄位,包括其他衍生欄位,只要該表達式不直接或間接地參考自身即可。
衍生欄位可以出現在表格定義中的任何位置。衍生欄位可以散佈在普通欄位之間。不必像上面範例所示,將衍生欄位放在表格定義中欄位列表的末尾。
衍生欄位不能具有預設值(不能使用「DEFAULT」子句)。衍生欄位的值始終是「AS」關鍵字後面的表達式所指定的值。
衍生欄位不能用作主鍵的一部分。(未來版本的 SQLite 可能會放寬對 STORED 欄位的此限制。)
衍生欄位的表達式只能參考同一列中的常數字面量和欄位,並且只能使用純量確定性函數。該表達式不能使用子查詢、聚合函數、視窗函數或表格值函數。
衍生欄位的表達式可以參考同一列中的其他衍生欄位,但任何衍生欄位都不能直接或間接地依賴自身。
產生的欄位的表達式不能直接參考 ROWID,但它可以參考 INTEGER PRIMARY KEY 欄位,而這兩者通常是相同的。
每個資料表必須至少有一個非產生的欄位。
無法使用 ALTER TABLE ADD COLUMN 新增 STORED 欄位。但是,可以新增 VIRTUAL 欄位。
產生欄位的資料型態和 排序序列 僅由欄位定義中的資料型態和 COLLATE 子句 決定。GENERATED ALWAYS AS 表達式的資料型態和排序序列不會影響欄位本身的資料型態和排序序列。
產生的欄位不包含在 PRAGMA table_info 陳述式提供的欄位清單中。但它們包含在較新的 PRAGMA table_xinfo 陳述式的輸出中。
SQLite 3.31.0 版 (2020-01-22) 新增了產生的欄位支援。如果較早版本的 SQLite 嘗試讀取綱要中包含產生的欄位的資料庫檔案,則該較早版本會將產生的欄位語法視為錯誤,並回報資料庫綱要已損毀。
更明確地說:SQLite 3.31.0 版可以讀取和寫入任何由 SQLite 3.0.0 (2004-06-18) 以來的任何先前版本建立的任何資料庫。此外,在 3.31.0 之前的較早版本的 SQLite 可以讀取和寫入由 SQLite 3.31.0 版和之後版本建立的資料庫,只要資料庫綱要不包含較早版本無法理解的功能(例如產生的欄位)。僅當您使用 SQLite 3.31.0 版或之後版本建立包含產生的欄位的新資料庫,然後嘗試使用不理解產生的欄位的較早版本的 SQLite 讀取或寫入該資料庫檔案時,才會發生問題。