一個 相關子查詢 是一個子查詢,其中包含對外部查詢中也出現的表格的引用。例如:
SELECT * FROM t1
WHERE column1 = ANY (SELECT column1 FROM t2
WHERE t2.column2 = t1.column2);請注意,即使子查詢的 FROM 子句沒有提及表格 t1,子查詢仍包含對 t1 的一個欄位的引用。因此,MySQL 會在子查詢外部尋找,並在外部查詢中找到 t1。
假設表格 t1 包含一列,其中 column1 = 5 且 column2 = 6;同時,表格 t2 包含一列,其中 column1 = 5 且 column2 = 7。簡單的表達式 ... WHERE column1 = ANY (SELECT column1 FROM t2) 會是 TRUE,但在這個範例中,子查詢內的 WHERE 子句是 FALSE(因為 (5,6) 不等於 (5,7)),因此整個表達式是 FALSE。
範圍規則: MySQL 從內到外進行評估。例如:
SELECT column1 FROM t1 AS x
WHERE x.column1 = (SELECT column1 FROM t2 AS x
WHERE x.column1 = (SELECT column1 FROM t3
WHERE x.column2 = t3.column1));在此陳述式中,x.column2 必須是表格 t2 中的欄位,因為 SELECT column1 FROM t2 AS x ... 重新命名了 t2。它不是表格 t1 中的欄位,因為 SELECT column1 FROM t1 ... 是一個更外層的外部查詢。
當 subquery_to_derived 標誌的 optimizer_switch 變數啟用時,最佳化器可以將相關的純量子查詢轉換為衍生表格。考慮這裡顯示的查詢:
SELECT * FROM t1
WHERE ( SELECT a FROM t2
WHERE t2.a=t1.a ) > 0;為了避免對給定的衍生表格進行多次實體化,我們可以改為將衍生表格實體化一次,該表格會從內部查詢中引用的表格(t2.a)的連接欄位新增分組,然後在提升的述詞(t1.a = derived.a)上進行外部聯結,以便選擇與外部列匹配的正確群組。(如果子查詢已經有明確的分組,則額外的分組會新增到分組清單的末尾。)因此,先前顯示的查詢可以改寫如下:
SELECT t1.* FROM t1
LEFT OUTER JOIN
(SELECT a, COUNT(*) AS ct FROM t2 GROUP BY a) AS derived
ON t1.a = derived.a
AND
REJECT_IF(
(ct > 1),
"ERROR 1242 (21000): Subquery returns more than 1 row"
)
WHERE derived.a > 0;在改寫後的查詢中,REJECT_IF() 代表一個內部函數,它會測試給定的條件(在這裡是比較 ct > 1),並且在條件為 true 時引發給定的錯誤(在此案例中為 ER_SUBQUERY_NO_1_ROW)。這反映了最佳化器在評估任何提升的述詞之前,作為評估 JOIN 或 WHERE 子句的一部分所執行的基數檢查,只有在子查詢回傳不超過一列時才會執行提升的述詞。
只有在滿足以下條件時,才能執行這種轉換:
子查詢可以是
SELECT清單、WHERE條件或HAVING條件的一部分,但不能是JOIN條件的一部分,也不能包含LIMIT或OFFSET子句。此外,子查詢不能包含任何集合運算,例如UNION。WHERE子句可能包含一個或多個述詞,並以AND組合。如果WHERE子句包含OR子句,則無法進行轉換。至少必須有一個WHERE子句述詞符合轉換的條件,而且它們都不能拒絕轉換。為了符合轉換的條件,
WHERE子句述詞必須是一個相等述詞,其中每個運算元都應該是一個簡單的欄位參考。其他述詞(包括其他比較述詞)都不符合轉換的條件。述詞必須使用等號運算子=來進行比較;在此情況下,不支援 null 安全的<=>運算子。只包含內部參考的
WHERE子句述詞不符合轉換的條件,因為它可以在分組之前進行評估。只包含外部參考的WHERE子句述詞符合轉換的條件,即使它可提升到外部查詢區塊。這是透過在衍生表格中新增一個沒有分組的基數檢查來實現的。為了符合轉換的條件,
WHERE子句述詞必須有一個只包含內部參考的運算元,以及一個只包含外部參考的運算元。如果述詞因為此規則而不符合條件,則會拒絕查詢的轉換。相關欄位只能存在於子查詢的
WHERE子句中(而不能存在於SELECT清單、JOIN或ORDER BY子句、GROUP BY清單或HAVING子句中)。子查詢的FROM清單中的衍生表格內也不能有任何相關欄位。相關欄位不能包含在彙總函數的引數清單中。
必須在直接包含正在考慮轉換的子查詢的查詢區塊中解析相關欄位。
相關欄位不能存在於
WHERE子句中的巢狀純量子查詢中。子查詢不能包含任何視窗函數,而且不能包含在子查詢外部的查詢區塊中彙總的任何彙總函數。如果
COUNT()彙總函數包含在子查詢的SELECT清單元素中,則必須位於最上層,且不能是表達式的一部分。
另請參閱 第 15.2.15.8 節,「衍生表格」。