LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

SQL語句高效去重寫法

admin
2025年7月31日 9:21 本文熱度 512

今天咱聊聊SQL里那些去重的招兒。平時查數據總遇到重復值,統計結果跑偏、存了一堆沒用的,頭疼得很。我整理了6個常用的去重關鍵字和操作,結合實際場景給你掰扯明白,保準你看完就知道該用哪個!

一、DISTINCT:單表去重的"快刀"

這玩意兒最簡單,直接把重復的行干掉。但記住一點:它是看所有選中列的組合,不是單看某一列。

舉個例子,員工表employees里有這些數據:

id  name    department
1   Alice   HR
2   Bob     Engineering
3   Alice   HR  -- 這行和1行name+department重復
4   Charlie Marketing

DISTINCT查姓名:

SELECT DISTINCT name FROM employees;

結果就只剩Alice、Bob、Charlie,重復的Alice被合并了。

要是查name+department

SELECT DISTINCT name, department FROM employees;

因為第3行和第1行的name+department完全一樣,所以只留一行。

優點:簡單直接,一行代碼搞定單表去重。
坑點:會隱式排序,數據量大了可能變慢;而且作用于所有選中的列,想只去重某一列但保留其他列?不行!

二、GROUP BY:帶統計功能的"去重+計算器"

GROUP BYDISTINCT靈活,不光能去重,還能順帶做統計(比如計數、求和)。

還是用上面的員工表,想統計每個部門有多少人:

SELECT department, COUNT(*) AS 人數 
FROM employees 
GROUP BY department;

結果會是:

HR            2
Engineering   2
Marketing     1

這其實就是按department分組,每組只留一條(去重),再算每組的數量。

和DISTINCT的區別

  • DISTINCT只去重,不統計;GROUP BY能分組+計算,適合需要分析數據的場景。
  • 大數據量時GROUP BY性能可能更好(尤其加了索引的話),因為它能按分組字段有序處理。

三、UNION vs UNION ALL:多表合并時的"過濾器"

這倆是用來合并多個查詢結果的,比如查兩個部門的員工,再合并到一起。

先建兩個表:

-- 人力資源部
hr_dept: id=1(Alice), id=2(David)
-- 工程部
eng_dept: id=2(David), id=3(Bob), id=1(Alice)

UNION合并:

SELECT name FROM hr_dept
UNION
SELECT name FROM eng_dept;

結果是Alice、David、Bob——重復的AliceDavid被自動去重了。

換成UNION ALL

SELECT name FROM hr_dept
UNION ALL
SELECT name FROM eng_dept;

結果會是Alice、David、David、Bob、Alice——原樣保留所有重復項,不做去重。

用法口訣

  • 確定沒重復,或者不需要去重?用UNION ALL,速度快(少了去重步驟)。
  • 怕有重復,必須去重?用UNION,但性能會差一點(要排序去重)。

四、EXCEPT / MINUS:找"差異"的利器

這倆是求差集:返回"第一個表有,第二個表沒有"的記錄,而且自動去重。

比如有兩個表:

all_products(所有產品): id=1(Laptop), 2(Phone), 3(Tablet)
sold_products(已售產品): id=1(Laptop), 3(Tablet)

想查"沒賣出去的產品",用EXCEPT(SQL Server/PostgreSQL):

SELECT * FROM all_products
EXCEPT
SELECT * FROM sold_products;

結果就一個id=2(Phone)

注意:Oracle用MINUS替代EXCEPT;MySQL不支持這倆,得用LEFT JOIN模擬:

-- MySQL替代方案
SELECT ap.* 
FROM all_products ap
LEFT JOIN sold_products sp ON ap.id = sp.id
WHERE sp.id IS NULL;  -- 只留沒匹配上的

五、INTERSECT:找"交集"的工具

返回兩個表都有的記錄,自動去重。比如查"所有會員"和"活躍會員"的重疊部分:

all_members(所有會員): id=1(Tom), 2(Jerry), 3(Spike)
active_members(活躍會員): id=1(Tom), 3(Spike), 4(Tyke)

INTERSECT(Oracle/SQL Server支持):

SELECT * FROM all_members
INTERSECT
SELECT * FROM active_members;

結果是id=1(Tom)、3(Spike)——這倆在兩個表都出現了。

MySQL同樣不支持,用INNER JOIN模擬:

SELECT am.* 
FROM all_members am
INNER JOIN active_members ac ON am.id = ac.id;

六、窗口函數:復雜去重的"手術刀"

上面的方法對付簡單場景夠了,但遇到"保留每組最新一條"這種需求,就得用ROW_NUMBER()這類窗口函數了。

比如訂單表orders,想按用戶分組,只留每個用戶最新的訂單:

id  user_id  order_time
1   100      2023-01-01
2   100      2023-01-05  -- 這個用戶的最新訂單
3   200      2023-01-03

ROW_NUMBER()給每組排序,再取第一條:

SELECT * FROM (
  SELECT *,
    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_time DESCAS rn
  FROM orders
) t 
WHERE rn = 1;  -- 只留每組排序第一的(最新的)

結果會留下id=2(user_id=100的最新訂單)和id=3(user_id=200的唯一訂單)。

不同數據庫的"脾氣"得注意

有些方法不是所有數據庫都支持,比如:

  • MySQL沒有EXCEPTINTERSECT,得用JOIN模擬;
  • Oracle用MINUS代替EXCEPT
  • ROW_NUMBER()在MySQL 8.0+才支持,老版本不行。

場景速查表:啥時候用啥招?

場景
推薦方法
例子片段
單表去重看結果
DISTINCT
SELECT DISTINCT dept FROM emp
單表去重+統計(如計數)
GROUP BY
SELECT dept, COUNT(*) FROM emp GROUP BY dept
多表合并后去重
UNION
SELECT name FROM A UNION SELECT name FROM B
多表合并不需要去重
UNION ALL
同上,把UNION換成UNION ALL
找A有但B沒有的數據
EXCEPT/MINUS(或模擬)
SELECT * FROM A EXCEPT SELECT * FROM B
找A和B都有的數據
INTERSECT(或模擬)
SELECT * FROM A INTERSECT SELECT * FROM B
保留每組最新/最早的記錄
ROW_NUMBER()
PARTITION BY user_id ORDER BY time DESC

最后說句大實話

去重不是越復雜越好,得看數據量和需求:

  • 小數據量、簡單去重:DISTINCT足夠;
  • 要統計分析:GROUP BY更合適;
  • 多表合并:優先UNION ALL(快),需要去重再用UNION
  • 復雜邏輯(如保留最新記錄):窗口函數ROW_NUMBER()是王道。

記住這些,下次遇到重復數據,你就知道該拔刀還是用手術刀了!


該文章在 2025/7/31 9:21:50 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
亚洲中文字幕一二三区 | 中文字幕在线精品视频入口一区 | 宅男宅女精品视频一区二区 | 一本久久精品久久 | 亚洲日韩国产精品综合区 | 伊久香蕉在线视频网站 |