Oracle rank()over(),dense_rank()over(),row_number()over()排序

今天在力扣上做題時,遇到點麻煩,經過查看別人的評論,發現涉及到了我的知識盲區,所以去找了下資料,做了一個總結。
先看下題目,題目來源力扣,點此鏈接到力扣題目

編寫一個 SQL 查詢,獲取 Employee 表中第二高的薪水(Salary) 。

+----+--------+
| Id | Salary |
+----+--------+
| 1  | 100    |
| 2  | 200    |
| 3  | 300    |
+----+--------+
例如上述 Employee 表,SQL查詢應該返回 200 作爲第二高的薪水。如果不存在第二高的薪水,那麼查詢應返回 null+---------------------+
| SecondHighestSalary |
+---------------------+
| 200                 |
+---------------------+

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/second-highest-salary

首先,簡單來看這是一併不復雜的查詢,力扣標註難度也是簡單,但是下面有道題目是查詢第n高的題目,難度中等,那麼做這道簡單的題目的時候我們就要考慮到通用性了,就是說,我們要寫出來一個框架,想要查第幾高就可以查第幾高。

所以排除了一些只查詢第二高或者看起來比較麻煩的做法,比如:先查出來最高的,然後把這個值作爲條件,再查詢出來比這個小的裏面最大的,就是第二高的。這個做法是可行的,但是如果我要第三高的呢,第四高的呢,繼續這樣嵌套下去也是可以的,但是感覺很麻煩。

然後我嘗試用單純的rownum嵌套做,但是遇到了一個奇怪的問題,我在自己的電腦上創建表做實驗,是可以查詢到第二高的薪水,但是提交到力扣的時候,不管是升序還是降序,rownum<=2都是100,200,只能放棄。
翻看別人的解題思路,讓我認識到了一個新的思路,就是rank()over(),dense_rank()over(),row_number()over()。那麼這三個函數與over搭配有什麼用呢,我們直接執行語句看一下結果就一目瞭然了。
首先,創建一個表:

create table Employee(
id number,
salary varchar2(50))

好,然後我們插入數據,爲了結果更直觀,我們多插入幾條:

insert into  employee values(1,'100');
insert into  employee values(2,'200');
insert into  employee values(3,'300');
insert into  employee values(4,'400');
insert into  employee values(5,'200');
insert into  employee values(6,'100');
insert into  employee values(7,'400');
insert into  employee values(8,'300');

現在我們看下錶裏的數據
在這裏插入圖片描述
好,現在我們先來看下使用rank()over()的結果,over()用於排序

select id,salary,rank()over(order by salary desc) as rank_num from employee

結果如下:
在這裏插入圖片描述
看RANK_NUM那一列,我們看到了什麼,從最高到最低,中間是跳躍這排序的,id爲7的salary是400與id爲4的salary是400的並列第一,而id爲3的salary是300的排第3,也就是說,2被跳過去了。

好,看到了rank()over(),我們再看下dense_rank()over()

select id,salary,dense_rank()over(order by salary desc) as dense_rank_num from employee;

使用dense_rank()over()結果如下:
在這裏插入圖片描述
我們看到DENSE_RANK_NUM這列,salary是400的兩個並列第一,salary是300的兩個並列第二,這時候其實我們就知道,這道題就是用這個了。

我們再看下row_number()over()這個函數

select id,salary,row_number()over(order by salary desc) as row_num from employee;

看下結果:
在這裏插入圖片描述
他是1,2,3,4。。。這樣順序往下排的。
好,簡單瞭解了這三個排序函數之後,我們應該怎麼做這道題呢,首先可以確定的是,我們現在需要的是dense_rank()over()這個函數,那麼我們先用這個排序看下

select Salary,dense_rank()over( order by Salary desc) as dense_rank from Employee

在這裏插入圖片描述
然後把查詢出的結果作爲一張表,查詢出dense_rank=2的salary

select salary from (select Salary,dense_rank()over( order by Salary desc) as dense_rank from Employee)where DENSE_RANK=2;

結果如下:
在這裏插入圖片描述
然後我們發現有兩條重複的結果,我們只需要一條就可以了,所以使用distinct去重。

select distinct salary from (select Salary,dense_rank()over( order by Salary desc) as dense_rank from Employee)where DENSE_RANK=2;

這時候,取出第二高的工資已經完成了,但是還有個問題待解決,那就是如果沒有第二高的工資,顯示NULL,該怎麼做呢。我們先把所有的數據刪除掉,只留下一行數據。

我們知道,oracle有個函數叫NVL(str1,str2)當str1有值時,返回str1的值,當str1無值時,返回str2的值,現在,我們需要他。

select NVL((select distinct salary from (select Salary,dense_rank()over( order by Salary desc) as dense_rank from Employee)where DENSE_RANK=2),NULL) from dual;

好,到這一步,基本就算完成了,不過這樣提交還是不行的,因爲我們的輸出不完全符合題意,我們需要給查詢出的結果起一個別名,最終結果如下:

select NVL((select distinct Salary from (select Salary,dense_rank()over( order by Salary desc) as dense_rank from Employee) where DENSE_RANK=2),NULL) as "SecondHighestSalary"  from dual;

哈哈,提交,搞定!
在這裏插入圖片描述

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