萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 子查詢實戰:WHERE/HAVING/IN/EXISTS/FROM 完整範例解析

子查詢是 SQL 進階應用的核心,MySQL 支援在 WHERE、HAVING、IN、EXISTS、FROM 等子句中嵌套查詢。理解各場景的差異與最佳實踐,能寫出高效且可維護的複雜查詢。本文詳細解析五大常見用法並提供實戰範例。

一、WHERE / HAVING 子查詢

子查詢置於圓括號內,優先級高於比較/邏輯運算符。HAVING 用於分組後過濾,WHERE 用於分組前過濾。

核心差異:

  • WHERE:聚合前過濾列,不可包含聚合函數。
  • HAVING:聚合後過濾組,通常包含聚合函數。

若無 GROUP BY,兩者結果相同,但語義不同,建議語義正確使用。

-- WHERE 範例
SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE status='active');

-- HAVING 範例
SELECT department, AVG(salary) AS avg_sal
FROM employees
GROUP BY department
HAVING AVG(salary) > (SELECT AVG(salary) FROM employees);

二、IN / NOT IN 子查詢

當子查詢回傳多行單列值時,必須使用 IN 而非 =。

SELECT id, title FROM article
WHERE id IN (428,429,430,431,432);

-- 動態子查詢
SELECT id, title FROM article
WHERE id IN (SELECT article_id FROM article_tag WHERE tag_id=135);

三、EXISTS / NOT EXISTS 子查詢

EXISTS 僅檢查子查詢是否回傳至少一行,不關心具體值,常用於關聯存在性檢查,效能通常優於 IN(特別是大資料集)。

SELECT c.CustomerId, c.CompanyName
FROM Customers c
WHERE EXISTS (
    SELECT 1 FROM Orders o
    WHERE o.CustomerID = c.CustomerID
);

注意:子查詢常用 SELECT 1 或 SELECT *,避免不必要的列投影。

四、FROM 子查詢(導出表)

子查詢結果作為臨時表參與外層查詢,必須指定別名。

SELECT a.id, a.title
FROM article a
JOIN (
    SELECT article_id FROM article_tag WHERE tag_id=135
) AS tbt ON a.id = tbt.article_id;

五、效能與最佳實踐建議

  1. 優先使用 JOIN 替代 IN/EXISTS 子查詢(MySQL 優化器對 JOIN 處理更成熟)。
  2. EXISTS 通常優於 IN,尤其外層大表、內層小表時。
  3. 避免在 WHERE 中對大表使用不相關子查詢,改用連接或 EXISTS。
  4. 導出表 (FROM 子查詢) 若資料量大,考慮建立臨時表或物化視圖。
  5. 確保子查詢條件列有適當索引。

靈活運用子查詢能解決許多複雜業務邏輯,但務必配合 EXPLAIN 分析執行計畫,避免效能陷阱。

copyright © 萬盛學電腦網 all rights reserved