APPLY 允許將右側表值函數/子查詢套用至左側表的每一行,邏輯處理順序固定為先左後右(異於 JOIN 可交換順序)。這使得右側運算式可引用左側欄位,解決 JOIN 無法處理的「每行動態計算」場景。
| 運算子 | 行為 | 相當於 |
|---|---|---|
| CROSS APPLY | 僅返回右側有結果的左側行 | INNER JOIN(但右側可引用左側欄位) |
| OUTER APPLY | 返回所有左側行,右側無結果填 NULL | LEFT JOIN(但右側可引用左側欄位) |
測試資料:
-- Category: Id, Name
-- CategoryDetail: Id, CategoryId, Cry
INSERT Category VALUES (1,'Cat'), (2,'Dog'), (3,'Tiger');
INSERT CategoryDetail VALUES (1,1,'喵'), (2,2,'汪');
-- Tiger (Id=3) 無對應明細
SELECT * FROM dbo.Category a
OUTER APPLY (SELECT * FROM dbo.CategoryDetail b WHERE b.CategoryId = a.Id) AS c;

Tiger 行保留,右側欄位為 NULL。
SELECT * FROM dbo.Category a
CROSS APPLY (SELECT * FROM dbo.CategoryDetail b WHERE b.CategoryId = a.Id) AS c;

僅返回 Cat、Dog 兩行。
-- LEFT JOIN 寫法
SELECT * FROM dbo.Category a
LEFT JOIN dbo.CategoryDetail b ON b.CategoryId = a.Id;

結果與 OUTER APPLY 相同。
| 維度 | OUTER APPLY | LEFT JOIN |
|---|---|---|
| 右側運算式 | 任意複雜子查詢、表值函數、預存程序 | 僅限資料表/檢視表 |
| 引用左側欄位 | 原生支援 | 需移至 WHERE/ON 子句,受限 |
| 效能 | 較慢(逐行執行右側邏輯) | 較快(集合式運算,優化器支援完善) |
| 可讀性 | 複雜邏輯集中封裝 | 標準 SQL,廣為人知 |
LEFT JOIN 效能優於 OUTER APPLY。優化器對 JOIN 有成熟的演算法選擇(Hash/Merge/Nested Loops),而 APPLY 多為 Nested Loops 逐行執行。建議:能用 LEFT JOIN 解決的場景優先用 JOIN,僅在需封裝複雜邏輯/呼叫函數時使用 APPLY。
資料庫相容性層級需 ≥ 90(SQL Server 2005+)。
CREATE FUNCTION fn_GetTopOrders(@CustomerId INT, @TopN INT)
RETURNS TABLE AS RETURN
SELECT TOP (@TopN) * FROM Orders WHERE CustomerId = @CustomerId ORDER BY OrderDate DESC;
-- 每位客戶最新 3 筆訂單
SELECT c.*, o.*
FROM Customers c
CROSS APPLY fn_GetTopOrders(c.CustomerId, 3) o;
此場景無法用 JOIN 替代,展現 APPLY 獨特價值。