參考地址: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 表名 別名;
或者在排序前進行空值處理都可以
排序函數的使用注意
- 排名函數必須有 OVER 子句。
- 排名函數必須有包含 ORDER BY 的 OVER 子句。
- 分組內從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想怎麼搞怎麼搞
總結(碼字)不易,幫助到了你,給個贊~~~~~