首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL UNION 子句中 ORDER BY 限制繞過方案:子查詢別名法詳解

     編輯:MySQL 資料庫相關知識

問題現象

-- 需求:取某 ID 附近的前後各 1 條記錄
(SELECT id, title FROM subjects WHERE id > 100 ORDER BY id LIMIT 1)
UNION
(SELECT id, title FROM subjects WHERE id < 100 ORDER BY id DESC LIMIT 1);
-- ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY

根因

MySQL 語法規定:**UNION 直接包含的 SELECT 不允許單獨使用 ORDER BY**,除非配合 LIMIT。但即使加 LIMIT,單獨 ORDER BY 也會報錯。

標準繞過方案:子查詢 + 別名

SELECT * FROM (
    SELECT id, title FROM subjects WHERE id > 100 ORDER BY id LIMIT 1
) AS t1
UNION
SELECT id, title FROM subjects WHERE id < 100 ORDER BY id DESC LIMIT 1;

關鍵點

  1. 第一個 SELECT 包裹在 ( ... ) AS t1 中
  2. 衍生表必須有別名 (AS t1),否則報 Every derived table must have its own alias
  3. 外層無需 ORDER BY,UNION 保持子查詢順序
  4. 第二個 SELECT 因不在 UNION 直接層級,可正常使用 ORDER BY

完整對比:三種寫法

寫法SQL結果
直接 UNION + ORDER BYSELECT ... ORDER BY ... LIMIT 1 UNION SELECT ... ORDER BY ... LIMIT 1❌ 語法錯誤
第一子查詢加括號無別名(SELECT ... ORDER BY ... LIMIT 1) UNION SELECT ... ORDER BY ... LIMIT 1❌ Every derived table must have its own alias
第一子查詢加別名(SELECT ... ORDER BY ... LIMIT 1) AS t1 UNION SELECT ... ORDER BY ... LIMIT 1✅ 成功

進階:UNION ALL + 全局排序

-- 若需最終結果按 id 排序
SELECT * FROM (
    SELECT id, title FROM subjects WHERE id > 100 ORDER BY id LIMIT 1
) AS t1
UNION ALL
SELECT id, title FROM subjects WHERE id < 100 ORDER BY id DESC LIMIT 1
ORDER BY id;  -- 全局排序 (MySQL 8.0+ 支援 UNION 後 ORDER BY)

UNION vs UNION ALL 性能

  • UNION:去重 (臨時表 + 排序/哈希),較慢
  • UNION ALL:不去重,直接合併結果集,**優先使用**
  • 業務確定無重複時,必須用 UNION ALL

適用場景擴展

  1. 分頁查詢合併:不同條件取 Top-N 合併展示
  2. 異構表合併:結構相同的分表/歸檔表數據合併
  3. 優先級查詢:高優先級數據 UNION ALL 低優先級補齊

避坑提醒

  1. 列數、類型、順序必須一致:否則報錯或隱式轉換導致數據錯誤
  2. 衍生表物化開銷:大結果集子查詢會創建臨時表,評估是否應用層合併更優
  3. MySQL 8.0+ CTE 寫法更優雅:
    WITH next_rec AS (SELECT ... WHERE id > 100 ORDER BY id LIMIT 1),
         prev_rec AS (SELECT ... WHERE id < 100 ORDER BY id DESC LIMIT 1)
    SELECT * FROM next_rec UNION ALL SELECT * FROM prev_rec;

UNION 中 ORDER BY 限制是 MySQL 歷史語法遺留,**子查詢別名法** 是通用繞過方案。現代應用優先考慮 **CTE (WITH)** 或 **應用層合併**,代碼更清晰、優化器更友好。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved