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

MySQL GROUP BY 與 ORDER BY 執行順序深度解析:取每組最新記錄的正確姿勢

     編輯:MySQL 資料庫相關知識

MySQL 中 GROUP BY 執行於 SELECT 之前、ORDER BY 之後,導致「分組後取最新記錄」的直觀寫法失效。本文透過執行順序分析、錯誤示範、三種正確解法完整解析。

SQL 執行順序 vs 書寫順序

書寫順序執行順序說明
1. SELECT5. SELECT投影欄位
2. FROM1. FROM確定數據源
3. WHERE2. WHERE行過濾
4. GROUP BY3. GROUP BY分組聚合
5. HAVING4. HAVING分組過濾
6. ORDER BY6. ORDER BY結果排序
7. LIMIT7. LIMIT限制行數

關鍵結論: ORDER BY 在 GROUP BY 之後執行,無法影響分組內「取哪一行」。

錯誤示範

-- 錯誤:想取每個分類最新文章
SELECT * FROM test GROUP BY category_id ORDER BY `date` DESC;

-- 實際行為:
-- 1. GROUP BY 先執行,每組任意取一行 (通常是物理存儲第一行)
-- 2. ORDER BY 再對這些「任意行」排序
-- 結果:非各組最新記錄

解法一:子查詢先排序再分組 (最直觀)

SELECT * FROM (
    SELECT * FROM `test` ORDER BY `date` DESC
) AS temp
GROUP BY category_id
ORDER BY `date` DESC;

原理: 內層先按時間倒序,外層 GROUP BY 取每組第一行 (即最新)。

適用: 中小數據量、邏輯簡單、MySQL 5.7 預設 ONLY_FULL_GROUP_BY 可能報錯需調整。

解法二:GROUP_CONCAT + 子查詢 (不依賴 ONLY_FULL_GROUP_BY)

SELECT * FROM `test` 
WHERE id IN (
    SELECT SUBSTRING_INDEX(
        GROUP_CONCAT(id ORDER BY `date` DESC), ',', 1
    )
    FROM `test` 
    GROUP BY category_id
)
ORDER BY `date` DESC;

原理:

  1. GROUP_CONCAT(id ORDER BY date DESC):組內按時間串聯 ID
  2. SUBSTRING_INDEX(..., ',', 1):取第一個 ID (最新)
  3. 外層 IN 精確匹配

注意: group_concat_max_len 預設 1024 字元,大組需調大:SET SESSION group_concat_max_len = 1000000;

解法三:JOIN 衍生表 (效能最佳,大數據量推薦)

SELECT t1.* 
FROM `test` t1
JOIN (
    SELECT category_id, MAX(`date`) AS max_date
    FROM `test`
    GROUP BY category_id
) t2 ON t1.category_id = t2.category_id AND t1.`date` = t2.max_date
ORDER BY t1.`date` DESC;

優勢:

  • 標準 SQL,跨資料庫相容
  • 可利用 (category_id, date) 複合索引
  • 無 ONLY_FULL_GROUP_BY 問題
  • 大表效能穩定

解法四:MySQL 8.0 窗口函數 (現代標準)

WITH ranked AS (
    SELECT *, 
           ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY `date` DESC) AS rn
    FROM `test`
)
SELECT * FROM ranked WHERE rn = 1 ORDER BY `date` DESC;

優勢: 語義最清晰、效能優秀、支援並列處理 (RANK()/DENSE_RANK())。

效能對比與選型建議

方案適用版本效能可讀性推薦場景
子查詢先排序5.0+中 (臨時表)高小表、快速開發
GROUP_CONCAT5.0+中低 (字串操作)中中表、無窗口函數環境
JOIN 聚合全版本高 (索引友好)高大表、生產環境標準
窗口函數8.0+最高最高新專案、複雜分組邏輯

實戰範例:商品變更記錄取最新

SELECT * FROM (
    SELECT * FROM `ecm_copy_goods_change` ORDER BY `cid` DESC
) `ecm_copy_goods_change` 
GROUP BY goods_id 
ORDER BY `cid` DESC;
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved