工做記錄之 oracle去重的三個方法

工做中常常會使用sql分組,總結三個方法:sql

一、distinct數據庫

在 SQL 中,關鍵字 distinct 用於返回惟一不一樣的值。其語法格式爲:express

SELECT DISTINCT 列名稱 FROM 表名稱

假設有一個表「CESHIDEMO」,包含兩個字段,分別 NAME 和 AGE,具體格式以下:oracle

CESHIDEMO

觀察以上的表,我們會發現:擁有相同 NAME 的記錄有兩條,擁有相同 AGE 的記錄有三條。若是我們運行下面這條 SQL 語句,函數

/**
* 其中 PPPRDER 爲 Schema 的名字,即表 CESHIDEMO 在 PPPRDER 中
*/
 
select name from PPPRDER.CESHIDEMO

將會獲得以下結果:測試

name

觀察該結果,我們會發如今以上的四條記錄中,包含兩條 NAME 值相同的記錄,即第 2 條記錄和第 3 條記錄的值都爲「gavin」。那麼,若是我們想讓擁有相同 NAME 的記錄只顯示一條該如何實現呢?這時,就須要用到 distinct 關鍵字啦!接下來,運行以下 SQL 語句,spa

select distinct name from PPPRDER.CESHIDEMO

將會獲得以下結果:code

distinct

觀察該結果,顯然我們的要求獲得實現啦!可是,我們不由會想到,若是將 distinct 關鍵字同時做用在兩個字段上將會產生什麼效果呢?既然想到了,我們就試試唄,運行以下 SQL 語句,blog

select distinct name, age from PPPRDER.CESHIDEMO

獲得的結果以下所示:排序

nameandage

觀察該結果,哎呀,貌似沒有做用啊?她將所有的記錄都顯示出來了啊!其中 NAME 值相同的記錄有兩條,AGE 值相同的記錄有三條,徹底沒有變化啊!但事實上,結果就應該是這樣的。由於當 distinct 做用在多個字段的時候,她只會將全部字段值都相同的記錄「去重」掉,顯然我們「可憐」的四條記錄並不知足該條件,所以 distinct 會認爲上面四條記錄並不相同。空口無憑,接下來,我們再向表「CESHIDEMO」中添加一條徹底相同的記錄,驗證一下便可。添加一條記錄後的表以下所示:

添加一條記錄

再運行以下的 SQL 語句,

select distinct name, age from PPPRDER.CESHIDEMO

獲得的結果以下所示:

nameandage

觀察該結果,完美的驗證了我們上面的結論。

此外,有一點須要你們特別注意,即:關鍵字 distinct 只能放在 SQL 語句中全部字段的最前面才能起做用,若是放錯位置,SQL 不會報錯,但也不會起到任何效果。

二、row_number() over()

在 oracle數據庫中,爲我們提供了一個函數 row_number() 用於給數據庫表中的記錄進行標號,在使用的時候,其後還跟着一個函數 over(),而函數 over() 的做用是將表中的記錄進行分組和排序。二者使用的語法爲:

ROW_NUMBER() OVER(PARTITION BY COLUMN1 ORDER BY COLUMN2)

意爲:將表中的記錄按字段 COLUMN1進行分組,按字段 COLUMN2 進行排序,其中

PARTITION BY:表示分組ORDER BY:表示排序

接下來,我們還用表「CESHIDEMO」中的數據進行測試。首先,給出沒有使用 row_number() over() 函數時查詢的結果,以下所示:

添加一條記錄

而後,運行以下 SQL 語句,

select PPPRDER.CESHIDEMO.*, row_number() over(partition by age order by name desc) from PPPRDER.CESHIDEMO

獲得的結果以下所示:

函數

從上面的結果能夠看出,其在原表的基礎上,多了一列標有數字排序的列。那麼反過來分析我們運行的 SQL 語句,發現其確實按字段 AGE 的值進行分組了,也按字段 NAME 的值進行排序啦!所以,函數的功能獲得了驗證。

接下來,我們就研究如何用 row_number() over() 函數實現「去重」的功能。經過觀察上面的結果,我們能夠發現,若是以 NAME 分組,以 AGE 排序,而後再取每組的第一個記錄或許就能夠實現「去重」的功能啊!那麼試試看,運行以下 SQL 語句,

/*
* 其中 rn 表示最後添加的那一列
*/
 
select * from
(select PPPRDER.CESHIDEMO.*, row_number() over(partition by name order by age desc) rn from PPPRDER.CESHIDEMO)
where rn = 1

運行後,獲得的結果以下所示:

rn

 

三、group by

 

GROUP BY語句用來與聚合函數(aggregate functions such as COUNT, SUM, AVG, MIN, or MAX.)聯合使用來獲得一個或多個列的結果集。

語法以下:

SELECT column1, column2, ... column_n, aggregate_function (expression)            

FROM tables            

WHERE predicates            

GROUP BY column1, column2, ... column_n;

 

舉例

好比說咱們有一個學生表格(student),包含學號(id),課程(course),分數(score)等等多個列,咱們想經過查詢獲得每一個學生選了幾門課程,此時咱們就能夠聯合使用COUNT函數與GROUP BY語句來獲得這一結果

SELECT id, COUNT(course) as numcourse

FROM student

GROUP BY id

由於咱們是使用學號來進行分組的,這樣COUNT函數就是在以學號分組的前提下來實現的,經過COUNT(course)就能夠計算每個學號對應的課程數。

 

注意

由於聚合函數經過做用於一組數據而只返回一個單個值,所以,在SELECT語句中出現的元素要麼爲一個聚合函數的輸入值,要麼爲GROUP BY語句的參數,不然會出錯。

例如,對於上面提到的表格,咱們作一個這樣的查詢:

SELECT id, COUNT(course) as numcourse, score

FROM student

GROUP BY id

此時查詢便會出錯,錯誤提示以下:

Column ‘student.score' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

出現以上錯誤的緣由是由於一個學生id對應多個分數,若是咱們簡單的在SELECT語句中寫上score,則沒法判斷應該輸出哪個分數。若是想用score做爲select語句的參數能夠將它用做一個聚合函數的輸入值,以下例,咱們能夠獲得每一個學生所選的課程門數以及每一個學生的平均分數:

SELECT id, COUNT(course) as numcourse, AVG(score) as avgscore

FROM student

GROUP BY id

HAVING

HAVING語句一般與GROUP BY語句聯合使用,用來過濾由GROUP BY語句返回的記錄集。

HAVING語句的存在彌補了WHERE關鍵字不能與聚合函數聯合使用的不足。

語法:

SELECT column1, column2, ... column_n, aggregate_function (expression)
FROM tables
WHERE predicates
GROUP BY column1, column2, ... column_n
HAVING condition1 ... condition_n;

一樣使用本文中的學生表格,若是想查詢平均分高於80分的學生記錄能夠這樣寫:

SELECT id, COUNT(course) as numcourse, AVG(score) as avgscore

FROM student

GROUP BY id

HAVING AVG(score)>=80;

在這裏,若是用WHERE代替HAVING就會出錯

 

select t.a , min(t.b) , t.c  from table t 

group by  t.a,t.c

相關文章
相關標籤/搜索