小巧、快速、可靠。
選擇其中三項。
回傳 (RETURNING)

1. 概述

returning 子句

RETURNING expr AS column-alias * ,

表達式

RETURNING 子句本身不是一個語句,而是一個可以選擇性地出現在頂層 DELETEINSERTUPDATE 語句末尾附近的子句。 RETURNING 子句的作用是使語句為每個被刪除、插入或更新的資料庫列回傳一個結果列。 RETURNING 不是標準 SQL,它是一個擴充功能。SQLite 的 RETURNING 語法參考了 PostgreSQL

SQLite 自 3.35.0 版 (2021-03-12) 起支援 RETURNING 語法。

1.1. 典型用法

RETURNING 子句旨在向應用程式提供由 SQLite 自動填入的欄位值。例如:

CREATE TABLE t0(
  a INTEGER PRIMARY KEY,
  b DATE DEFAULT CURRENT_TIMESTAMP,
  c INTEGER
);
INSERT INTO t0(c) VALUES(random()) RETURNING *;

在上面的 INSERT 語句中,SQLite 會計算所有三個欄位的值。 RETURNING 子句會使 SQLite 將選擇的值回報給應用程式。這可以避免應用程式必須發出單獨的查詢來找出插入的確切值。

2. 細節

RETURNING 子句後接著一個以逗號分隔的表達式清單。這些表達式類似於 SELECT 語句 中 SELECT 關鍵字後面的表達式,因為它們定義了結果集中欄位的值。每個表達式定義一個欄位的值。每個表達式後面可以選擇性地接著一個 AS 子句,該子句決定結果欄位的名稱。特殊的「*」表達式會展開為被刪除、插入或更新的表格中所有非隱藏欄位的清單。

對於 INSERT 和 UPDATE 語句,對被修改表格中欄位的引用指的是套用變更*後*該欄位的值。對於 DELETE 語句,對欄位的引用指的是刪除發生*前*的值。

RETURNING 子句僅回傳被 DELETE、INSERT 或 UPDATE 語句直接修改的列。 RETURNING 子句不會回報由 外鍵約束觸發器 引起的任何其他資料庫變更。

UPSERT 的 RETURNING 子句會回報插入和更新的列。

2.1. 處理順序

當執行帶有 RETURNING 子句的 DELETE、INSERT 或 UPDATE 語句時,所有資料庫變更都會在第一次呼叫 sqlite3_step() 期間發生。 RETURNING 子句的輸出會累積在記憶體中。第一次 sqlite3_step() 呼叫會回傳 RETURNING 輸出的一列,後續的 RETURNING 輸出列則由後續呼叫 sqlite3_step() 回傳。換句話說,所有 RETURNING 子句的輸出都會延後到所有資料庫修改動作完成之後才會回傳。

這表示如果一個敘述句包含 RETURNING 子句,且該子句會產生大量的輸出(例如大量的資料列、大型字串或 BLOB 值),則該敘述句在執行時可能會使用大量的暫存記憶體來儲存這些值。

雖然 SQLite 保證所有資料庫異動都會在任何 RETURNING 輸出發出之前發生,但它*不*保證個別 RETURNING 資料列的順序會與這些資料列在資料庫中異動的順序相符。RETURNING 資料列的輸出順序是任意的,且不一定與資料列在內部處理的順序相關。

2.2. 自我參照子查詢是不確定的

SQLite 保證所有資料庫異動都會在任何 RETURNING 輸出*發出*之前發生,但 SQLite 不保證資料庫異動發生的順序,也不保證 RETURNING 輸出相對於這些資料庫異動*計算*的時機。RETURNING 子句的輸出都是在第一次呼叫 sqlite3_step() 時計算並放置在暫存儲存區中,但這些輸出計算的特定順序以及資料庫異動發生的順序並未指定。順序可能會在不同的查詢之間有所改變。

因此,如果 RETURNING 輸出的欄位包含參照正在修改之資料表的子查詢,則該子查詢的結果可能會取決於未指定的行為,因此在每次呼叫查詢時可能會有所不同。

2.3. ACID 異動

前面「*處理順序*」章節提到「資料庫異動發生在第一次呼叫 sqlite3_step() 時」,這表示異動會儲存在執行該敘述句的資料庫連線的私有頁面快取中。這*並不*表示異動實際上已提交。提交不會在敘述句完成之前發生,即使敘述句是較大交易的一部分,也可能不會提交。資料庫的異動仍然是原子性、一致性、隔離性和持久性 (ACID)。前面章節提到「異動發生」時,表示內部資料結構已調整,等待交易提交。這些異動中的一部分可能會或可能不會溢出到預寫式日誌,具體取決於頁面快取的壓力程度。如果頁面快取沒有記憶體壓力,則可能在交易完成(即 sqlite3_step() 返回 SQLITE_DONE 之後)之前都不會寫入任何內容到磁碟。

換句話說,前面章節提到「資料庫異動發生」時,表示異動發生在執行該敘述句的特定資料庫連線的記憶體中,*而不是*表示異動已寫入磁碟。

3. 限制和注意事項

  1. RETURNING 子句無法用於針對虛擬資料表的 DELETE 和 UPDATE 敘述句。此限制可能會在 SQLite 的未來版本中移除。

  2. RETURNING 子句僅適用於最上層的 DELETE、INSERT 和 UPDATE 敘述句。觸發程序中的敘述句無法使用 RETURNING 子句。

  3. 即使包含 RETURNING 子句的 DML 敘述句會返回資料表內容,它也不能用作子查詢。RETURNING 子句只能將資料返回給應用程式。目前無法將 RETURNING 輸出轉移到另一個資料表或查詢。PostgreSQL 可以像通用表表達式中的視圖一樣使用包含 RETURNING 子句的 DML 敘述句。SQLite 目前沒有此功能,但這可能會在未來的版本中新增。

  4. RETURNING 子句發出的資料列以任意順序出現。該順序可能會根據資料庫結構描述、所使用的特定 SQLite 版本,甚至在同一敘述句的不同執行之間而有所改變。沒有辦法讓輸出資料列以特定順序出現。即使使用SQLITE_ENABLE_UPDATE_DELETE_LIMIT選項編譯 SQLite,允許在 DELETE 和 UPDATE 敘述句中使用 ORDER BY 子句,這些 ORDER BY 子句也不會限制 RETURNING 的輸出順序。

  5. RETURNING 子句所發出的值是頂層 DELETE、INSERT 或 UPDATE 陳述式所看到的值,並不反映由觸發程序所做的任何後續值變更。因此,如果資料庫包含在每一列插入或更新後修改某些值的 AFTER 觸發程序,RETURNING 子句會發出在這些觸發程序執行之前計算的原始值。

  6. RETURNING 子句不能包含頂層的聚合函數窗口函數。如果 RETURNING 子句中有子查詢,這些子查詢可以包含聚合函數和窗口函數,但聚合函數不能出現在頂層。

  7. RETURNING 子句只能參考正在被修改的表格。在 UPDATE FROM 陳述式中,FROM 子句中命名的輔助表格不能參與 RETURNING 子句。