萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL DISTINCT 去重完全指南:單欄位、多欄位、COUNT 配合、GROUP BY 替代方案與 LIMIT 陷阱

DISTINCT 基礎語法

-- 單欄位去重
SELECT DISTINCT column FROM table;

-- 多欄位去重(組合唯一)
SELECT DISTINCT col1, col2 FROM table;

-- 統計不重複值個數
SELECT COUNT(DISTINCT column) FROM table;

核心誤區:DISTINCT 作用於所有列出欄位的組合

SELECT DISTINCT a, b FROM t 返回的是 (a,b) 元組不重複,而非「a 不重複且保留對應的 b」。

測試驗證

CREATE TABLE student (name VARCHAR(20), age INT);
INSERT INTO student VALUES ('a',5), ('a',5), ('c',0);

SELECT DISTINCT name, age FROM student;
-- 結果:(a,5), (c,0)  -- 兩列同時相同才去重

-- 若想「name 不重複,取任意 age」
SELECT name, MAX(age) FROM student GROUP BY name;
-- 結果:(a,5), (c,0)

GROUP BY 替代 DISTINCT 獲取完整行資料

需求:依某欄位去重,同時返回其他欄位(任意值或聚合值)。

-- 取每個 name 的最新記錄(假設有 id 自增)
SELECT * FROM student
WHERE id IN (SELECT MAX(id) FROM student GROUP BY name);

-- 或使用變數模擬 ROW_NUMBER (MySQL 8.0+ 直接用窗口函數)
SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY id DESC) AS rn
    FROM student
) t WHERE rn = 1;

GROUP BY 進階:HAVING 過濾分組、LIMIT 分頁

-- 統計每首歌被多少歌手演唱,只顯示 >=2 的,按次數降序取前 10
SELECT songname, singerid, COUNT(*) AS cnt
FROM t_song
GROUP BY songname, singerid
HAVING cnt >= 2
ORDER BY cnt DESC, songid ASC
LIMIT 10;

關鍵點:LIMIT 作用於 GROUP BY/HAVING/ORDER BY 之後的結果集,而非原始行。

DISTINCT 與 COUNT 組合寫法等價

SELECT COUNT(DISTINCT songid) FROM feedback;
SELECT COUNT(DISTINCT(songid)) FROM feedback;  -- 兩者等價

聚合函數與空值處理

-- MAX/MIN 忽略 NULL,字串按字典序
SELECT MAX(singername) FROM feedback;  -- 非空最大值,'zxx' > 'lady'

-- 統計非空值個數
SELECT COUNT(singername) FROM feedback;  -- 不計 NULL

SQL 子句執行順序(邏輯順序)

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT

因此 SELECT 定義的別名可用於 ORDER BY、GROUP BY、HAVING,但不可用於 WHERE。

常見錯誤:COUNT(*) 轉換失敗

-- 原查詢
SELECT feedback_id, songid, MAX(singername), MAX(time) AS new_time
FROM feedback GROUP BY songid ORDER BY new_time DESC;

-- 錯誤改寫
SELECT COUNT(*) FROM feedback GROUP BY songid ORDER BY new_time DESC;
-- 報錯:Unknown column 'new_time' in 'order clause'
-- 原因:SELECT 列表變為 COUNT(*),new_time 別名不存在

最佳實踐清單

  • 單欄位去重值/計數 → DISTINCT
  • 多欄位組合去重 → DISTINCT col1, col2
  • 去重同時保留其他欄位 → GROUP BY + 聚合函數 / 窗口函數
  • 複雜去重邏輯 → CTE + ROW_NUMBER() (MySQL 8.0+)
  • 永遠記住 DISTINCT 作用於整個選取列表,而非單一欄位
copyright © 萬盛學電腦網 all rights reserved