SqlServer 在查詢結果中如何過濾掉重復數據


問題背景

在一個多表查詢的sql中正常情況下產生的數據都是唯一的,但因為數據庫中存在錯誤(某張表中存在相同的外鍵ID)導致我這邊查詢出來的數據就會有重復的問題
下面結果集中UserID:15834存在多個
 
查詢Sql如下:
SELECT *
FROM (
SELECT ROW_NUMBER() OVER ( ORDER BY T.USERID asc )AS Row
,T.USERID
,T.CreateTime
FROM UserInfo T
LEFT JOIN DiseaseInfo i ON i.UserID=T.UserID
) TT WHERE TT.Row between 0 AND 20 ORDER BY UserID DESC

 

解決方法:
參考下面新的解決方案
在網絡上了解到MSSql中通過關鍵字“ PARTITION BY” 可以將查詢結果集進行分區處理,然后在查詢結果集時就可以過濾掉重復的記錄了(如果有指定分區字段則區ID相同)
通過更改后的Sql,在Over中添加 PARTITION BY T. USERID 以UserID進行分區,然后在查詢結果集時通過 DISTINCT ROW , 過濾掉重復的分區ID號
SELECT DISTINCT ROW ,*
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY T.USERID ORDER BY T.USERID asc )AS Row
,T.USERID
,T.CreateTime
FROM UserInfo T
LEFT JOIN DiseaseInfo i ON i.UserID=T.UserID
) TT WHERE TT.Row between 0 AND 12 ORDER BY UserID DESC

 

查詢時未過濾重復分區ID DISTINCT ROW , 下面的結果集跟上面的結果集不同(Row是進行過分區的所有有重復Row)
   
 
在查詢結果集時過 濾掉重復的分區ID號  DISTINCT ROW ,
 
 
 
新解決方案
 
由於在Sqlserver中如果多表聯合查詢中除非所有的字段都完全相同否則在使用 DISTINCT 用進行去重時還是會當成兩個不同的數據集進行處理,因此 DISTINCT 會失效即
如下面的結果集,雖然 USERID和其他字段內容相同但HID是不相同的所以無法使用 DISTINCT 進行去重
出現這種問題是因為數據庫設計的錯誤(正常情況下關聯表 HospitalInfo 中只可能存在一條 ClinicInfo 表對應的 記錄)
Sql語句:
SELECT *
FROM (
SELECT ROW_NUMBER() OVER ( order by T.USERID asc )AS Row
,T.USERID
,LEFT(T.Patient_Tel1,5)+'00000000' AS Tel
,T.CreateTime
,h.HName
,h.HID
fromUserInfo T
LEFT JOIN ClinicInfo c ON c.UserID=T.UserID AND C.Disabled=1
LEFT JOIN HospitalInfo H ON H.HID=c.VisitHospital WHERE T.Disabled=1
AND t.UserID>=17867 AND T.UserID<=17875
--(T.Patient_Tel1 like '%13800000000%')
) TT WHERE
TT.Row between 0and20

 

 
可以看到上面的結果集中Row是有重復的,其他Row為2的是跟第一個是重復的
 
因為數據庫涉及到其他業務和人員因此我只能提交該問題給相關的技術,但在該問題解決前不能影響到我這邊也出現此問題
於是在原sql基礎上進行處理,雖然 HospitalInfo 表中不重復記錄但表的自增ID是不可能重復的那我只需要最新的一條記錄即可
 
如果通過 DISTINCT 過進行去重則就無法成功,因為數據存在差別,可以看到第一條和最后一條數據還是重復的
SELECT DISTINCT row,*
FROM (
SELECT ROW_NUMBER() OVER ( partition by T.USERID order by T.USERID asc )AS Row
,T.USERID
,LEFT(T.Patient_Tel1,5)+'00000000' AS Tel
,T.CreateTime
,h.HName
,h.HID
fromUserInfo T
LEFT JOIN ClinicInfo c ON c.UserID=T.UserID AND C.Disabled=1
LEFT JOIN HospitalInfo H ON H.HID=c.VisitHospital WHERE T.Disabled=1
AND t.UserID>=17867 AND T.UserID<=17875
--(T.Patient_Tel1 like '%13800000000%')
) TT WHERE
--row=1 AND
TT.Row between 0 and 20 

 

 
更改后的Sql
 
SELECT *
FROM (
--partition by T.USERID 以UserID對結果集進行分區
SELECT ROW_NUMBER() OVER ( partition by T.USERID order by T.USERID asc )AS Row
,T.USERID
,LEFT(T.Patient_Tel1,5)+'00000000' AS Tel
,T.CreateTime
,h.HName
,h.HID
fromUserInfo T
LEFT JOIN ClinicInfo c ON c.UserID=T.UserID AND C.Disabled=1
LEFT JOIN HospitalInfo H ON H.HID=c.VisitHospital WHERE T.Disabled=1
AND t.UserID>=17867 AND T.UserID<=17875
--(T.Patient_Tel1 like '%13800000000%')
) TT WHERE
--因為之前已經以UserID對結果集進行分區,所以如果存在重復的字段則row的值會不相同
--row=1 AND

TT.Row between 0 and 20

 

USERID=17867相同經過分區后會存在不同的Row值
 
在對結果集再次過濾時添加條件 :  row=1, 已經將重復記錄中舊的數據過濾掉了 (HID:78)
 
 
根據新的解決方案解決了重復的問題,但又出現的新的問題即Row分區后都是重復的,而我再進行分頁的時候就無效了(因為此時結果集中的Row都是為1)
解決方案:在結果集再加一層查詢並加上ID號然后再對結果集進行分頁處理
 
-- 新增一層查詢解決過濾掉重復數據后無法分頁的問題
SELECT * FROM (
SELECT ROW_NUMBER() OVER (ORDER BY userid) AS RowNum,*
FROM (
--partition by T.USERID 以UserID對結果集進行分區
SELECT ROW_NUMBER() OVER ( partition by T.USERID order by T.USERID asc )AS Row
,T.USERID
,LEFT(T.Patient_Tel1,5)+'00000000' AS Tel
,T.CreateTime
,h.HName
,h.HID
fromUserInfo T
LEFT JOIN ClinicInfo c ON c.UserID=T.UserID AND C.Disabled=1
LEFT JOIN HospitalInfo H ON H.HID=c.VisitHospital WHERE T.Disabled=1
AND t.UserID>=17867 AND T.UserID<=20875
--(T.Patient_Tel1 like '%13800000000%')
) TT
)AS T
WHERE
--過濾重復數據
Row=1
--對結果進行分頁
AND RowNum between 13 and 24

 

 
參考:






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM