子查詢是嵌套在另一個 SQL 陳述式內部的 `SELECT` 敘述,可出現在 `WHERE`、`FROM`、`SELECT` 清單、`HAVING` 等子句中。外部查詢稱為主查詢,內部稱為子查詢。
-- 找出與 Brazil 同區域的國家 SELECT name FROM bbc WHERE region = (SELECT region FROM bbc WHERE name = 'Brazil');
若 `bbc` 表有兩筆 `name='Brazil'` (不同區域),子查詢回傳兩個區域值,外部 `region = (...)` 會拋錯:`Subquery returns more than 1 value`。
-- IN:集合成員資格測試 SELECT name FROM bbc WHERE region IN (SELECT region FROM bbc WHERE name = 'Brazil'); -- EXISTS:存在性測試 (通常效能較好,尤其 NOT EXISTS) SELECT name FROM bbc WHERE EXISTS (SELECT 1 FROM bbc b2 WHERE b2.name = 'Brazil' AND b2.region = bbc.region);
SELECT name FROM bbc WHERE population > (SELECT population FROM bbc WHERE name = 'Russia');
SELECT * FROM bbc
WHERE region IN (SELECT region FROM bbc WHERE name IN ('India','Iran'));
SELECT name FROM bbc WHERE region = 'Europe' AND gdp/population > (SELECT gdp/population FROM bbc WHERE name = 'United Kingdom');
| 類型 | 位置 | 回傳 | 優化提示 |
|---|---|---|---|
| 純量子查詢 | SELECT 清單、WHERE (單值比較) | 單一值 | 確保唯一索引/約束,避免多列錯誤 |
| 資料列子查詢 | WHERE (IN/EXISTS) | 單欄多列 | 優先用 EXISTS (相關) 或 JOIN 改寫 |
| 資料表子查詢 (衍生表) | FROM | 多欄多列 | 加上別名,考慮物化為 CTE/暫存表 |
| 相關子查詢 | WHERE/SELECT (參考外部欄位) | 依外部列執行 | 易造成 Nested Loops 慢查詢,改寫為 JOIN/APPLY |
-- 相關子查詢 (慢)
SELECT c.CustomerName,
(SELECT MAX(OrderDate) FROM Orders o WHERE o.CustomerID = c.CustomerID) AS LastOrder
FROM Customers c;
-- 改寫為 OUTER APPLY (SQL Server 專用,語意相同但可回多欄)
SELECT c.CustomerName, oa.LastOrder
FROM Customers c
OUTER APPLY (
SELECT MAX(OrderDate) AS LastOrder FROM Orders o WHERE o.CustomerID = c.CustomerID
) oa;
-- 或 LEFT JOIN 衍生表
SELECT c.CustomerName, d.LastOrder
FROM Customers c
LEFT JOIN (
SELECT CustomerID, MAX(OrderDate) AS LastOrder FROM Orders GROUP BY CustomerID
) d ON c.CustomerID = d.CustomerID;
子查詢表達力強但易寫出效能陷阱。掌握「純量單值 vs 集合」、「相關 vs 非相關」、「IN/EXISTS 選擇」、「改寫為 JOIN/APPLY」四大維度,即可寫出正確且高效的 SQL。