Oracle中的排序和排序函數的使用

參考地址:https://www.cnblogs.com/qiuting/p/7880500.html

前排提示,下面的實例用到的hr.employees表是Oracle11g的orcl實例自帶的表空間的表,不要說你沒有~要是沒有,你可能Oracle沒裝好,或者賬號連查看這個表的權限都沒有,你換個sysman等身份的賬號進行登錄,然後測試

 

普通SQL排序

Oracle本身對SQL有良好的支持,因此簡單的排序,就可以使用order by子句

select * from hr.employess order by salary ;

排序後獲得序號(row_num)

如果要求是排序,然後還要有一個專門的列給這些結果標序號,怎麼辦?

使用Oracle的rownum關鍵字和列名一起查詢即可:

select rownum as rank, e.*  from hr.employees e order by salary desc ;

然而不能像上面直接這樣查,會出現這種結果

因爲rownum的機制的問題

 

正確的做法:嵌套一層子查詢,先排序完,然後以這個排序好了的結果作爲基表,再進行一次查詢

select rownum as rank, e.* from 
(select * from hr.employees order by salary desc) e;

這下就沒問題了

 

 

使用排序函數

爲什麼使用排序函數?

有了上面的rownum關鍵字爲什麼還要有排序函數呢?請看上面的運行結果

應用場景考慮

排序的場景要考慮如下:

值不同的情況下:這個是最完美的情況了,現實肯定不可能。

有相同的值:按先來後到,這在一些比賽可能可以;或者並列第幾,這個在成績排名中是肯定的,不然分數一樣,我憑什麼我第二他第一,這個時候就只能使用Oracle的排序函數了

row_number()函數

row_number的用途非常廣泛,排序最好用它,它會爲查詢出來的每一行記錄生成一個序號,依次排序且不會重複,注意使用row_number函數時必須要用over子句選擇對某一列進行排序才能生成序號。

row_number的簡單使用

語法

select 別名.*, row_number() over(order by 子句 ) from 表名 別名;

實例

select e.*, row_number() over ( order by e.salary desc ) as rank from  hr.employees e ;

上面查看Oracle自帶的僱員表中的員工按工資降序排序,但是以然不能解決我們需要並列排名的問題

row_number的分組排序

語法

select 別名.*, row_number() over(partition by 別名.排序字段 order by 子句 ) from 表名 別名;

實際操作

簡單按工資降序別的也可以,那麼你可以分組排序嗎?例如我查看不同部們的人在他們自己的部門的工資排序,怎麼寫?

select e.*, row_number() over (partition by e.department_id order by e.salary desc ) as rank from  hr.employees e ;

加入了partiton by 通過哪個字段進行分組,然後排序,然而依然沒有解決並列排名的問題!

rank()函數-主要解決over子句排序字段值相同的情況

rank函數用於返回結果集的分區內每行的排名,行的排名是相關行之前的排名數加一。簡單來說rank函數就是對查詢出來的記錄進行排名,與row_number函數不同的是,rank函數考慮到了over子句中排序字段值相同的情況,如果使用rank函數來生成序號,over子句中排序字段值相同的序號是一樣的,後面字段值不相同的序號將跳過相同的排名號排下一個,也就是相關行之前的排名數加一,可以理解爲根據當前的記錄數生成序號,後面的記錄依此類推。

rank()的簡單使用

語法

select 別名.*, rank() over(order by 子句 ) from 表名 別名;

實例

select e.*, rank() over ( order by e.salary desc ) as rank from  hr.employees e ;

上面的sql語句不但進行了排序,而且對字段值相同的情況做出了排序相同的處理,然而,卻是1224的尷尬局面

rank的分組

rank的分組和row_number的分組一樣,在over子句中加入partition by子句即可

語法

select 別名.*, rank() over(partition by 別名.分組字段 order by 子句 ) from 表名 別名;

實例

select e.*, rank() over (partition by e.department_id order by e.salary desc ) as rank from  hr.employees e ;

 

那麼,有沒有支持1223的排序函數呢?dense_rank函數!

 

dense_rank函數

dense_rank函數的功能與rank函數類似,dense_rank函數在生成序號時是連續的,而rank函數生成的序號有可能不連續。dense_rank函數出現相同排名時,將不跳過相同排名號rank值緊接上一次的rank值。在各個分組內,rank()是跳躍排序,有兩個第一名時接下來就是第三名,dense_rank()是連續排序,有兩個第一名時仍然跟着第二名。

dense_rank的基本使用

語法

select 別名.*, dense_rank() over(order by 子句 ) from 表名 別名;

實際操作

select e.*, dense_rank() over ( order by e.salary desc ) as rank from  hr.employees e ;

 

dense_rank的分組排序

語法

select 別名.*, rank() over(partition by 別名.分組字段 order by 子句 ) from 表名 別名;

實際操作

select e.*, dense_rank() over (partition by e.department_id order by e.salary desc ) as rank from  hr.employees e ;

 

 

 

關於parttion by

  parttion by關鍵字是Oracle中分析性函數的一部分,用於給結果集進行分區。它和聚合函數Group by不同的地方在於它只是將原始數據進行名次排列,能夠返回一個分組中的條記錄(記錄數不變),而Group by是對原始數據進行聚合統計,一般只有一條反映統計值的結果(每組返回一條)

 

使用排序函數的時候,空值是最大的,如果排序字段爲null, 可能造成null字段排在最前面,影響排序結果。可以這樣:

select 別名.*, row_number() over(partition by 別名.分組字段 order by 子句 nulls last) from 表名 別名;
select 別名.*, rank() over(partition by 別名.分組字段 order by 子句 nulls last ) from 表名 別名;
select 別名.*, dense_rank() over(partition by 別名.分組字段 order by 子句 nulls last ) from 表名 別名;

或者在排序前進行空值處理都可以

排序函數的使用注意

  1. 排名函數必須有 OVER 子句。
  2. 排名函數必須有包含 ORDER BY 的 OVER 子句。
  3. 分組內從1開始排序。

 

總結

不使用函數排序

使用SQL自己的group by和order by子句等進行"排序" "分組和排序":

      比較麻煩,而且不能處理排序字段的值相同時的情況

使用Oracle的rownum關鍵字+sql的排序:

     能夠給查詢的記錄排序,並且給排序好的記錄打上123這種序號,但也比較麻煩,需要在排序好的基礎上再進行一次嵌套查詢

使用函數排序

使用row_number函數:

           可以排序,還可以分組排序,寫起來比普通的sql的簡潔的多,而且可以給排序的字段加序號,缺點是也無法處理排序字段的值相同時的情況

使用rank函數:

            有row_number一樣的效果,語法也相近,能處理排序字段的值相同時的情況,但是卻是1224的模式(即相同的序號後面的序號會被跳過,也可以理解爲佔用)

使用dens_rank函數:

            有row_number一樣的效果,語法也相近,能處理排序字段的值相同時的情況,是1223的模式(即相同的序號後面的序號不會跳過)

三種函數的各自支持的模式的使用

1234還是1223還是1224要看具體的應用場景,沒有說哪個就最好

要是1234是“先來後到”的規則的時候可以使用      假設是先到先得,那就算你成績和我一樣,你也不能有脾氣

1224是“名額或者資源有限的”情況下用     假設獎勵排名是第一到第五,就五張獎狀,只能12245了

1223是“名額或資源充足”的時候用            假設獎勵排名是第一到第五,獎狀很多,就可以12222333344445555想怎麼搞怎麼搞

 

 

總結(碼字)不易,幫助到了你,給個贊~~~~~

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章