UNION 合併多個 SELECT 結果集,去重(DISTINCT)或保留重複(ALL)。掌握其排序、分頁、欄位對齊規則,能寫出高效、正確的聯合查詢。
SELECT col1, col2 FROM t1
UNION [ALL | DISTINCT]
SELECT col1, col2 FROM t2
[UNION ...]
[ORDER BY col1 [DESC]]
[LIMIT n];
UNION = UNION DISTINCT(去重,需排序/哈希,較慢)。UNION ALL 直接拼接,效能遠優於 UNION,確定無重複時必用 ALL。(SELECT * FROM t1 ORDER BY id LIMIT 10)
UNION
(SELECT * FROM t2 ORDER BY id LIMIT 10);
-- 結果順序不保證,LIMIT 只對單側生效
SELECT * FROM (
SELECT * FROM t1
UNION ALL
SELECT * FROM t2
) AS u
ORDER BY u.id DESC
LIMIT 20;
-- 正確:用第一個 SELECT 的別名
(SELECT a AS b FROM t1) UNION (SELECT ...) ORDER BY b;
-- 錯誤:用原欄位名
(SELECT a AS b FROM t1) UNION (SELECT ...) ORDER BY a; -- Unknown column 'a'
部落格置頂文章優先,再按時間倒序分頁。
(
SELECT *, 1 AS ord FROM posts WHERE is_top = 1 ORDER BY created_at DESC
)
UNION ALL
(
SELECT *, 2 AS ord FROM posts WHERE is_top = 0 ORDER BY created_at DESC
)
ORDER BY ord, created_at DESC
LIMIT 10 OFFSET 0;
ord 分組再排序。UNION ALL 避免去重開銷(置頂與普通互斥)。SELECT * FROM (
(SELECT *, 1 AS grp FROM posts ORDER BY clicks DESC LIMIT 3)
UNION ALL
(SELECT *, 2 AS grp FROM posts ORDER BY created_at DESC)
) AS u
ORDER BY u.grp,
CASE u.grp WHEN 1 THEN u.clicks END DESC,
CASE u.grp WHEN 2 THEN u.created_at END DESC;
| 寫法 | 執行計畫關鍵字 | 適用場景 |
|---|---|---|
| UNION DISTINCT | Using temporary; Using filesort | 需去重、小結果集 |
| UNION ALL | 無臨時表/排序 | 已知無重複、大結果集、高頻介面 |
| 子查詢各自 LIMIT + 外層 ORDER BY LIMIT | 各子查詢用索引,外層小結果集排序 | 分頁、置頂、異構數據源合併 |
UNION ALL,確有重複才改 UNION。CAST 對齊,避免隱式轉換導致索引失效。ORDER BY/LIMIT,子查詢僅做資料準備。UNION ALL + 應用層分頁,避免深分頁 OFFSET 掃描。善用 UNION ALL + 外層排序分頁,即可優雅解決「多源合併、置頂優先、異構排序」等複雜查詢需求。