場景:四張表 A(a,b)、B(a,c)、C(a,d)、D(d,e)。需求:輸出 A 所有行,關聯 B 統計 a 出現次數,經 C 關聯 D 取 D.a。結果集含 A.a, A.b, B_count, D.a,無匹配時計數顯示 0。
SELECT
A.a,
A.b,
IFNULL(B.cnt, 0) AS b_count,
D.a AS d_a
FROM (
SELECT 1 AS a, 1 AS b UNION ALL
SELECT 2, 2 UNION ALL
SELECT 3, 4 UNION ALL
SELECT 4, 6
) AS A
LEFT JOIN (
SELECT a, COUNT(*) AS cnt
FROM (
SELECT 1 AS a, 1 AS c UNION ALL
SELECT 1, 3 UNION ALL
SELECT 1, 4 UNION ALL
SELECT 2, 1
) AS B
GROUP BY a
) AS B ON A.a = B.a
JOIN (
SELECT 1 AS a, 'A' AS d UNION ALL
SELECT 2, 'B' UNION ALL
SELECT 3, 'C' UNION ALL
SELECT 4, 'D'
) AS C ON A.a = C.a
JOIN (
SELECT 'A' AS d, 1 AS a UNION ALL
SELECT 'B', 2 UNION ALL
SELECT 'C', 3 UNION ALL
SELECT 'D', 4
) AS D ON C.d = D.d;
(SELECT ... UNION ALL ...) AS alias 在查詢中構建臨時結果集,避免建實體表。GROUP BY a 計數,再 LEFT JOIN 到 A,**避免一對多膨脹導致重複計數**。B.cnt 為 NULL。IFNULL(B.cnt, 0) 將無匹配計數轉為 0,符合業務語義。d 欄位橋接 D,最終取 D.a。INDEX idx_B_a (a)、INDEX idx_C_a (a)、INDEX idx_D_d (d)。WHERE 子句下推到派生表內部(MySQL 5.6+ derived_merge 優化)。SELECT *,僅選必要欄位減少網路與臨時表開銷。JOIN 時用 STRAIGHT_JOIN 固定驅動順序。| A.a | A.b | B_count | D.a |
|---|---|---|---|
| 1 | 1 | 3 | 1 |
| 2 | 2 | 1 | 2 |
| 3 | 4 | 0 | 3 |
| 4 | 6 | 0 | 4 |
完全符合預期:A 表 4 行全保留,B 計數正確,無匹配顯示 0,D.a 正確關聯。