子查詢是 SQL 進階應用的核心,MySQL 支援在 WHERE、HAVING、IN、EXISTS、FROM 等子句中嵌套查詢。理解各場景的差異與最佳實踐,能寫出高效且可維護的複雜查詢。本文詳細解析五大常見用法並提供實戰範例。
子查詢置於圓括號內,優先級高於比較/邏輯運算符。HAVING 用於分組後過濾,WHERE 用於分組前過濾。
若無 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 而非 =。
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 僅檢查子查詢是否回傳至少一行,不關心具體值,常用於關聯存在性檢查,效能通常優於 IN(特別是大資料集)。
SELECT c.CustomerId, c.CompanyName
FROM Customers c
WHERE EXISTS (
SELECT 1 FROM Orders o
WHERE o.CustomerID = c.CustomerID
);
注意:子查詢常用 SELECT 1 或 SELECT *,避免不必要的列投影。
子查詢結果作為臨時表參與外層查詢,必須指定別名。
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;
JOIN 替代 IN/EXISTS 子查詢(MySQL 優化器對 JOIN 處理更成熟)。EXISTS 通常優於 IN,尤其外層大表、內層小表時。WHERE 中對大表使用不相關子查詢,改用連接或 EXISTS。FROM 子查詢) 若資料量大,考慮建立臨時表或物化視圖。靈活運用子查詢能解決許多複雜業務邏輯,但務必配合 EXPLAIN 分析執行計畫,避免效能陷阱。