SQL SELECT DISTINCT 去重的實(shí)現(xiàn)
一、為什么需要數(shù)據(jù)去重?
在日常數(shù)據(jù)庫(kù)操作中,我們經(jīng)常會(huì)遇到這樣的場(chǎng)景:查詢客戶表時(shí)發(fā)現(xiàn)重復(fù)的郵箱地址,統(tǒng)計(jì)銷售數(shù)據(jù)時(shí)出現(xiàn)冗余的訂單記錄,分析用戶行為時(shí)碰到相同的訪問日志。這些重復(fù)數(shù)據(jù)不僅影響數(shù)據(jù)分析的準(zhǔn)確性,還會(huì)導(dǎo)致以下問題:
- 統(tǒng)計(jì)結(jié)果失真(如重復(fù)計(jì)算用戶數(shù)量)
- 報(bào)表生成效率降低
- 存儲(chǔ)空間浪費(fèi)
- 業(yè)務(wù)邏輯判斷錯(cuò)誤
此時(shí),SELECT DISTINCT 就像一把精準(zhǔn)的篩子,能夠幫助我們過濾掉冗余數(shù)據(jù),保留唯一值。下面通過一個(gè)具體案例感受其威力:
-- 原始數(shù)據(jù)包含重復(fù)記錄 SELECT product_category FROM sales; /* +-----------------+ | product_category| +-----------------+ | Electronics | | Clothing | | Electronics | | Home & Kitchen | | Clothing | +-----------------+ */ -- 使用DISTINCT去重后 SELECT DISTINCT product_category FROM sales; /* +-----------------+ | product_category| +-----------------+ | Electronics | | Clothing | | Home & Kitchen | +-----------------+ */
二、語(yǔ)法深度解析
基礎(chǔ)語(yǔ)法結(jié)構(gòu)
SELECT DISTINCT
column1,
column2,
...
FROM
table_name
[WHERE condition]
[ORDER BY column_name(s)]
[LIMIT number];
多列去重機(jī)制
當(dāng)指定多個(gè)列時(shí),DISTINCT會(huì)組合這些列的值進(jìn)行去重:
-- 創(chuàng)建示例表
CREATE TABLE employees (
id INT PRIMARY KEY,
dept VARCHAR(50),
position VARCHAR(50)
);
INSERT INTO employees VALUES
(1, 'HR', 'Manager'),
(2, 'IT', 'Developer'),
(3, 'HR', 'Manager'),
(4, 'Finance', 'Analyst');
-- 多列去重查詢
SELECT DISTINCT dept, position
FROM employees;
/*
+---------+-----------+
| dept | position |
+---------+-----------+
| HR | Manager |
| IT | Developer |
| Finance | Analyst |
+---------+-----------+
*/
NULL處理策略
不同數(shù)據(jù)庫(kù)對(duì)NULL值的處理存在差異:
| 數(shù)據(jù)庫(kù) | NULL處理方式 |
|---|---|
| MySQL | 多個(gè)NULL視為相同值 |
| PostgreSQL | 多個(gè)NULL視為相同值 |
| Oracle | 多個(gè)NULL視為相同值 |
| SQL Server | 多個(gè)NULL視為相同值 |
示例:
-- 插入包含NULL值的測(cè)試數(shù)據(jù) INSERT INTO employees VALUES (5, NULL, 'Intern'), (6, NULL, 'Intern'); SELECT DISTINCT dept, position FROM employees WHERE position = 'Intern'; /* +------+----------+ | dept | position | +------+----------+ | NULL | Intern | +------+----------+ */
三、進(jìn)階應(yīng)用技巧
1. 與聚合函數(shù)結(jié)合
-- 統(tǒng)計(jì)不重復(fù)的部門數(shù)量 SELECT COUNT(DISTINCT dept) AS unique_departments FROM employees; /* +---------------------+ | unique_departments | +---------------------+ | 3 | +---------------------+ */
2. 窗口函數(shù)中的去重
-- 配合ROW_NUMBER()實(shí)現(xiàn)高級(jí)去重
WITH ranked_employees AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY dept, position
ORDER BY id DESC
) AS rn
FROM employees
)
SELECT id, dept, position
FROM ranked_employees
WHERE rn = 1;
3. 性能優(yōu)化方案
當(dāng)處理海量數(shù)據(jù)時(shí),可以嘗試以下優(yōu)化策略:
- 建立覆蓋索引:
CREATE INDEX idx_dept_position ON employees(dept, position);
- 臨時(shí)表分階段處理:
CREATE TEMPORARY TABLE temp_unique AS SELECT DISTINCT dept, position FROM employees; -- 后續(xù)操作使用臨時(shí)表
四、常見誤區(qū)解析
誤區(qū)1:DISTINCT能提升查詢性能
實(shí)際上,DISTINCT操作需要經(jīng)過以下處理步驟:
- 全表掃描或索引掃描
- 創(chuàng)建臨時(shí)哈希表
- 比較和過濾重復(fù)值
- 結(jié)果排序(隱式或顯式)
當(dāng)數(shù)據(jù)量達(dá)到百萬級(jí)時(shí),一個(gè)不加限制的DISTINCT查詢可能導(dǎo)致嚴(yán)重的性能問題。
誤區(qū)2:DISTINCT與GROUP BY等價(jià)
雖然兩者都能實(shí)現(xiàn)去重,但存在本質(zhì)區(qū)別:
| 特性 | DISTINCT | GROUP BY |
|---|---|---|
| 主要用途 | 去重 | 分組聚合 |
| 排序保證 | 不保證 | 通常分組后有序 |
| 聚合函數(shù)使用 | 不能直接使用 | 必須配合使用 |
| 執(zhí)行計(jì)劃 | 可能使用排序 | 常使用哈希聚合 |
性能對(duì)比實(shí)驗(yàn)(TPC-H數(shù)據(jù)集):
-- 使用DISTINCT SELECT DISTINCT l_orderkey FROM lineitem WHERE l_shipdate BETWEEN '1998-01-01' AND '1998-12-31'; -- 執(zhí)行時(shí)間:2.34秒 -- 使用GROUP BY SELECT l_orderkey FROM lineitem WHERE l_shipdate BETWEEN '1998-01-01' AND '1998-12-31' GROUP BY l_orderkey; -- 執(zhí)行時(shí)間:1.87秒
五、最佳實(shí)踐指南
適用場(chǎng)景推薦
- 生成下拉菜單的可選值列表
- 數(shù)據(jù)清洗階段的重復(fù)檢測(cè)
- 數(shù)據(jù)探查時(shí)統(tǒng)計(jì)唯一值數(shù)量
- 關(guān)聯(lián)查詢前的維度表準(zhǔn)備
使用注意事項(xiàng)
- 字段選擇:僅選擇必要字段,避免無意義去重
- 排序影響:DISTINCT可能改變默認(rèn)排序
- 類型兼容:注意不同數(shù)據(jù)類型的比較規(guī)則
- 字符編碼:確保數(shù)據(jù)庫(kù)和連接的字符集一致
替代方案對(duì)比
| 方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|
| DISTINCT | 語(yǔ)法簡(jiǎn)單 | 大數(shù)據(jù)量性能差 |
| GROUP BY | 可結(jié)合聚合函數(shù) | 需要理解分組概念 |
| 臨時(shí)表 | 可重復(fù)利用中間結(jié)果 | 增加存儲(chǔ)開銷 |
| 窗口函數(shù) | 可靈活控制保留策略 | 語(yǔ)法復(fù)雜度高 |
六、實(shí)戰(zhàn)案例集錦
案例1:電商用戶行為分析
-- 識(shí)別訪問過不同品類商品的用戶
SELECT
user_id,
COUNT(DISTINCT product_category) AS visited_categories
FROM user_behavior_log
WHERE event_date >= CURDATE() - INTERVAL 7 DAY
GROUP BY user_id
HAVING visited_categories > 3;
案例2:金融交易監(jiān)控
-- 檢測(cè)異常重復(fù)交易
SELECT
DISTINCT t1.*
FROM transactions t1
JOIN transactions t2
ON t1.account_id = t2.account_id
AND t1.amount = t2.amount
AND ABS(TIMESTAMPDIFF(SECOND, t1.trans_time, t2.trans_time)) < 60
WHERE t1.trans_id <> t2.trans_id;
案例3:醫(yī)療數(shù)據(jù)清洗
-- 合并重復(fù)患者記錄
WITH duplicate_records AS (
SELECT
patient_id,
ROW_NUMBER() OVER (
PARTITION BY national_id, birth_date
ORDER BY created_at DESC
) AS rn
FROM medical_records
)
UPDATE medical_records
SET is_active = CASE WHEN rn = 1 THEN 1 ELSE 0 END;
七、總結(jié)與展望
通過本文的深度解析,我們?nèi)嬲莆樟薙ELECT DISTINCT的:
? 核心工作原理
? 多種應(yīng)用場(chǎng)景
? 性能優(yōu)化技巧
? 最佳實(shí)踐方案
隨著大數(shù)據(jù)時(shí)代的到來,數(shù)據(jù)去重技術(shù)也在不斷發(fā)展。值得關(guān)注的趨勢(shì)包括:
- AI智能去重:利用機(jī)器學(xué)習(xí)識(shí)別語(yǔ)義重復(fù)
- 實(shí)時(shí)去重引擎:Kafka等流處理平臺(tái)的去重方案
- 分布式去重算法:適應(yīng)海量數(shù)據(jù)的并行處理技術(shù)
最后提醒各位開發(fā)者:在數(shù)據(jù)科學(xué)項(xiàng)目中,約78%的時(shí)間花費(fèi)在數(shù)據(jù)清洗階段,而合理使用DISTINCT可以幫助節(jié)省至少23%的數(shù)據(jù)準(zhǔn)備時(shí)間。掌握這個(gè)看似簡(jiǎn)單的關(guān)鍵字,將會(huì)使你的數(shù)據(jù)庫(kù)操作事半功倍!
思考題:當(dāng)需要對(duì)10億條記錄進(jìn)行去重操作時(shí),除了使用DISTINCT,還有哪些更高效的實(shí)現(xiàn)方案?歡迎在評(píng)論區(qū)分享你的見解!
到此這篇關(guān)于SQL SELECT DISTINCT 去重的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SQL SELECT DISTINCT 去重內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
sqlServer實(shí)現(xiàn)分頁(yè)查詢的三種方式
在SqlServer中分頁(yè)查詢是經(jīng)常用到的查詢語(yǔ)句,一個(gè)好的分頁(yè)查詢語(yǔ)句,不能將代碼省略,下面這篇文章主要給大家介紹了關(guān)于sqlServer實(shí)現(xiàn)分頁(yè)查詢的三種方式,需要的朋友可以參考下2023-03-03
SQL Server中使用SQL語(yǔ)句實(shí)現(xiàn)把重復(fù)行數(shù)據(jù)合并為一行并用逗號(hào)分隔
這篇文章主要介紹了SQL Sever中使用SQL語(yǔ)句實(shí)現(xiàn)把重復(fù)行數(shù)據(jù)合并為一行并用逗號(hào)分隔,本文給出了兩種實(shí)現(xiàn)方式,需要的朋友可以參考下2015-02-02
SQL?Server數(shù)據(jù)庫(kù)創(chuàng)建表及其約束條件的操作方法
這篇文章主要介紹了SQL?Server?創(chuàng)建表及其約束條件,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11
Sql server中內(nèi)部函數(shù)fn_PhysLocFormatter存在解析錯(cuò)誤詳解
這篇文章主要給大家介紹了關(guān)于Sql server中內(nèi)部函數(shù)fn_PhysLocFormatter存在解析錯(cuò)誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-09-09
SQL Server無日志恢復(fù)數(shù)據(jù)庫(kù)(2種方法)
SQL Server數(shù)據(jù)庫(kù)中的日志文件可能會(huì)由于一些突發(fā)事件或者失誤造成丟失的嚴(yán)重后果,大家都知道,SQL Server數(shù)據(jù)庫(kù)中日志文件是很重要的,所以要及時(shí)的將丟失的日志文件給找回來。下文就為大家介紹一種恢復(fù)數(shù)據(jù)庫(kù)日志文件的方法。2015-08-08
SQL Server日志過大會(huì)影響查詢結(jié)果
一臺(tái)老Web服務(wù)器上,使用的是ASP+SQL Server 2000的網(wǎng)站,五六年了,使用起來一直很順暢,也就沒有怎么去理它。2009-05-05
SQL?server插入報(bào)錯(cuò):當(dāng)?IDENTITY_INSERT?設(shè)置為?OFF?時(shí)不能為表?‘XXX‘?
這篇文章主要介紹了SQL?server插入報(bào)錯(cuò):當(dāng)?IDENTITY_INSERT?設(shè)置為?OFF?時(shí),不能為表?‘XXX‘?中的標(biāo)識(shí)列插入顯式值的問題,該問題是給SQL server數(shù)據(jù)庫(kù)中的某個(gè)表插入數(shù)據(jù)引起的報(bào)錯(cuò),一般出現(xiàn)在該表為自增的情況下,本文給大家分享解決方法,需要的朋友可以參考下2023-09-09

