一個 相關子查詢 是一個子查詢,其中包含對外部查詢中也出現的表格的引用。例如:
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 節,「衍生表格」。