文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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

15.2.15.7 相關子查詢

一個 相關子查詢 是一個子查詢,其中包含對外部查詢中也出現的表格的引用。例如:

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

請注意,即使子查詢的 FROM 子句沒有提及表格 t1,子查詢仍包含對 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 子句中的巢狀純量子查詢中。

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

另請參閱 第 15.2.15.8 節,「衍生表格」