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

MySQL DISTINCT 去重進階:查詢多欄位不重複記錄的正確姿勢 MySQL DISTINCT 去重進階:查詢多欄位不重複記錄的正確姿勢

     編輯:MySQL 資料庫相關知識

DISTINCT 僅能針對 SELECT 清單的所有欄位組合去重,無法直接「指定某欄位去重並保留其他欄位」。本文揭露常見誤區,提供 GROUP BY、視窗函數、聚合函數三種正確解法,並說明適用場景。

常見誤區演示

-- 表結構
id | name
---|-----
1  | a
2  | b
3  | c
4  | c
5  | b

錯誤 1:DISTINCT 多欄位 = 組合去重

SELECT DISTINCT name, id FROM t;
/* 結果:5 筆全保留,因 (name,id) 組合皆唯一 */

錯誤 2:DISTINCT 放在欄位前

SELECT id, DISTINCT name FROM t; -- 語法錯誤,DISTINCT 必須緊接 SELECT

錯誤 3:WHERE 使用 DISTINCT

SELECT * FROM t WHERE DISTINCT name; -- 語法錯誤

正確解法一:GROUP BY(最通用、MySQL 所有版本)

-- 依 name 分組,取每組第一筆(MySQL 允許非聚合欄位不在 GROUP BY 中)
SELECT id, name FROM t GROUP BY name;
/* 結果:
id | name
---|-----
1  | a
2  | b
3  | c
*/
  • MySQL ONLY_FULL_GROUP_BY 模式(5.7+ 預設開啟)下需將非聚合欄位加入 GROUP BY 或用聚合函數:SELECT MIN(id), name FROM t GROUP BY name;
  • 若需確定取哪一筆(如最新、最大 ID),請用視窗函數(8.0+)或子查詢。

正確解法二:視窗函數 ROW_NUMBER()(MySQL 8.0+,精確控制)

WITH ranked AS (
  SELECT id, name,
         ROW_NUMBER() OVER (PARTITION BY name ORDER BY id) AS rn
  FROM t
)
SELECT id, name FROM ranked WHERE rn = 1;
/* 精確取每組最小 id 的那一筆,符合 ONLY_FULL_GROUP_BY */
  • 可靈活指定排序規則(ORDER BY id DESC 取最新)。
  • 標準 SQL,可移植至 PostgreSQL、SQL Server、Oracle。

正確解法三:聚合函數欺騙法(舊版變通,不推薦新專案)

SELECT *, COUNT(DISTINCT name) FROM t GROUP BY name;
/* 產生多一欄計數,但達到去重目的 */
  • 利用 COUNT(DISTINCT name) 強制分組,副作用是多出一欄。
  • 早期 MySQL 4.1 前無 GROUP_CONCAT、無視窗函數時的權宜之計。

進階:指定欄位去重並保留特定關聯欄位

-- 取每個 name 對應的最大 id 及其建立時間
SELECT name, MAX(id) AS max_id, MAX(created_at) AS latest_time
FROM t
GROUP BY name;

效能比較

方法適用版本精確度效能備註
GROUP BY所有取任意一筆(非確定)快舊版預設行為;新版需配合 ONLY_FULL_GROUP_BY
ROW_NUMBER()8.0+完全可控中(需排序)標準寫法,推薦新專案
聚合函數欺騙所有取任意一筆快產生多餘欄位,語意不清
JOIN 子查詢所有可控中SELECT * FROM t JOIN (SELECT name, MIN(id) AS id FROM t GROUP BY name) x USING (name,id)

最佳實務建議

  1. 新專案(MySQL 8.0+):優先使用 ROW_NUMBER() 視窗函數,語意清晰、標準相容。
  2. 舊版維護:GROUP BY 搭配 MIN()/MAX() 確定取值,或關閉 ONLY_FULL_GROUP_BY(不建議)。
  3. 避免在應用層用雙重迴圈查詢(N+1 問題),資料庫層解決去重效能高得多。
  4. 若頻繁需「依某欄位去重取最新」,考慮建立 UNIQUE KEY + ON DUPLICATE KEY UPDATE 寫入端去重,或維護物化視圖/摘要表。

理解 DISTINCT 作用於「整列組合」而非「單欄位」,選擇適合版本與業務精確度的去重方案,才能寫出正確且高效的 SQL。

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