公司面試題目之取出數據庫中重複的記錄
上圖高亮部分的是重複的數據行,那麼如何取出其中高亮的部分,
聚合函數
在解決這個問題前,我們必需先講講sql語言中一種特殊的函數:聚合函數,例如SUM, COUNT, MAX, AVG等。這些函數和其它函數的根本區別就是它們一般作用在多條記錄上。例如上函數從左至右依次爲 求總和,記錄數,最大值,平均值!關於它們的作用相信很多朋友也知道!但也有可能在自己知道的情況下,並不瞭解它們的學名,聚合函數。這也是我開篇寫這個的目的!
另外就是group by,分組查尋。看下面結果
通過使用GROUP BY 子句,可以讓SUM 這樣聚合函數對屬於一組的數據起作用。當我們上面指定 GROUP BY userName時,屬於同一個userName(用戶)的一組數據將只能返回一行值,也就是說,表中所有除userName(用戶)外的字段,只能通過 SUM, COUNT等聚合函數運算後返回一個值。假使我們在第二句SQL語句中添加一列,userPassword時,就會報如下錯誤
這應該是初學者經常遇見的錯誤,據上已經分析過,出現此種錯誤是必然,因爲,我們的結果是已經分組過的,所以結果會按姓名分組,相同的姓名只返回一行結果,但並沒有指定也按密碼分,所以當返回姓名重複記錄的時候,並不知道返回的這一行密碼取哪個?因爲我們沒有對密碼聚合,或分組,所以報錯是因爲密碼按此邏輯,無法取到!
那麼有朋友可以會想到那麼group by 後面再加上密碼會怎樣,可以試試。學計算機,有了想法就應該去嘗試,大膽嘗試。電腦也試不壞!怕什麼!
此時程序有了結果。對比之前的圖,我們可以發現結果集不一樣了,多了一行
a 15
變成了
a a 10
a b 5
想想原因,因爲我們現在 分組多加了密碼,所以也會按姓名和密碼都相同的分!因爲姓名都爲a的用戶有二個密碼爲a一個密碼爲b ,所以在按密碼分時,會繼續拆分!也就出現如上結果!
Having
那麼Having又是有什麼作用的?
HAVING子句主要就是在聚合後對組記錄進行篩選。類似where,但其與where又是不同的!
讓我們還是通過具體的實例來理解GROUP BY 和 HAVING 子句
第二句,也即將登錄總次數大於5的記錄查出!注意在這裏,我們不能使用where,因爲用where來限定條件,需要符合條件的列必須在表中存在!而這裏的取出總登錄次數大於5,表中本沒有這樣一列,所以無法使用where來查詢,而必須使用having,瞭解這個,我們就應該知道where與having的差別了!
HAVING是對由sum或其它聚合函數運算結果的輸出進行限制。
那麼在瞭解了上面的知識後,我們如何再來解決開篇提到的問題,也即如何取出表中重複的記錄?
我們要查出重複的記錄,那麼必然要用到分組查詢,group by。分組的依據爲表中各列。這樣它會將各列都相同的分爲一組,但同時我們要查詢出重複的記錄,因此必然需要相同的記錄至少應該是2條以上。由此可知。我們需要對group by 的結果進行限定,條件是記錄數大於1的,因此 我們聯想到having。因此有了如下解決方案:
那麼如果同時存在where及having是什麼樣的呢?看下圖:
還有另外一個相似的問題就是如何刪除數據庫中重複的記錄!
這個問題應該有幾種解決方案,比較常用的是使用臨時表,如下:
select distinct * into #temp from repeat
--刪除 repeat 表
delete repeat
--再從臨時表中取出所有結果放回repeat表中
insert repeat select * from #temp
--刪除臨時表
drop table #temp
操作之後的結果與上,去掉了重複的行我用高亮做了標記。也即使用distinct關鍵字去重,是去掉所有列都相同的,而對於userName及userPassword相同的,它沒有處理出來,現在假設要將姓名與密碼都相同的也去掉,如何處理。看下面:
select * from repeat a
where
(a.userName ) in (select userName from repeat group by userName,userPassword having count(*) > 1)
and
(a.userPassword ) in (select userPassword from repeat group by userName,userPassword having count(*) > 1)
這樣取出的是用戶名與密碼相同的記錄!將select改爲delete即可刪除,當然,這樣刪除就全部刪除了,如果想要留一條,還可在後面加限定條件,來決定留下哪一條!