文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  相關子查詢

15.2.15.7 相關子查詢

一個相關子查詢是一個包含對外部查詢也出現的表格的參照的子查詢。例如:

SELECT * FROM t1
  WHERE column1 = ANY (SELECT column1 FROM t2
                       WHERE t2.column2 = t1.column2);

請注意,子查詢包含對 t1 的欄位的參照,即使子查詢的 FROM 子句沒有提及表格 t1。因此,MySQL 會在子查詢之外尋找,並在外部查詢中找到 t1

假設表格 t1 包含一列,其中 column1 = 5column2 = 6;同時,表格 t2 包含一列,其中 column1 = 5column2 = 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)。這反映了最佳化器在評估 JOINWHERE 子句時執行的基數檢查,然後才評估任何提升的述詞,只有在子查詢不回傳多於一列時才會執行。

在滿足下列條件的情況下,可以執行此類型的轉換:

  • 子查詢可以是 SELECT 清單、WHERE 條件或 HAVING 條件的一部分,但不能是 JOIN 條件的一部分,且不能包含 LIMITOFFSET 子句。此外,子查詢不能包含任何集合運算,例如 UNION

  • WHERE 子句可能包含一個或多個以 AND 組合的述詞。如果 WHERE 子句包含 OR 子句,則無法轉換。至少有一個 WHERE 子句述詞必須符合轉換的資格,並且它們都不得拒絕轉換。

  • 為了符合轉換的資格,WHERE 子句述詞必須是一個相等述詞,其中每個運算元都應為簡單的欄位參照。其他述詞(包括其他比較述詞)均不符合轉換的資格。述詞必須使用相等運算子 = 進行比較;在此內容中不支援可安全處理 Null 值的 <=> 運算子。

  • 僅包含內部參照的 WHERE 子句述詞不符合轉換的資格,因為它可以在分組之前進行評估。即使可以將僅包含外部參照的 WHERE 子句述詞提升到外部查詢區塊,它也符合轉換的資格。這可以透過在衍生表格中新增沒有分組的基數檢查來實現。

  • 為了符合資格,WHERE 子句述詞必須有一個僅包含內部參照的運算元,以及一個僅包含外部參照的運算元。如果因為此規則而導致述詞不符合資格,則會拒絕查詢的轉換。

  • 相關的欄位只能出現在子查詢的 WHERE 子句中(而不能出現在 SELECT 清單、JOINORDER BY 子句、GROUP BY 清單或 HAVING 子句中)。子查詢的 FROM 清單中的衍生表格內也不能有任何相關的欄位。

  • 相關的欄位不能包含在彙總函式的引數清單中。

  • 相關的欄位必須在直接包含正在考慮轉換的子查詢的查詢區塊中解析。

  • 相關的欄位不能出現在 WHERE 子句中的巢狀純量子查詢中。

  • 子查詢不能包含任何視窗函式,且不得包含在子查詢外部的查詢區塊中彙總的任何彙總函式。如果子查詢的 SELECT 清單元素中包含 COUNT() 彙總函式,則必須位於最上層,且不能是表達式的一部分。

另請參閱第 15.2.15.8 節,〈衍生表格〉