开窗函数的意义与用法
開窗函數——排序函數
開窗函數與其他函數的區別是,它不是關聯其他表查詢,而是在一張表內根據我們的想法自定義的規則分組后對我們組內的數據進行檢索和計算。我們自定義的規則所分的組,就如同整張表的一個個小窗口,因此我們開出一個個小窗口并對這些小窗口進行的操作就叫做開窗函數。
開窗函數分為排序函數和聚合函數。
一、排序函數:
1.三個排序函數
句型:row_number()的排序函數
order_func OVER([PARTITION BY expression] ORDER BY clase)其中,order_func是指排序函數,包括:
row_number(),rank(),dense_rank(),ntile();
他們會為每一行返回一個序值。
PARTITION BY 是我們自定義的分組策略,如果不用,該函數會把其余select 語句包括where、having、group by的運行結果做為窗口進行排序;ORDER BY 是排序的方法,即每個窗口內根據哪個字段排序,不能缺省。
例如:我們需要對一個包含4個班級的16個同學的成績表進行以班為單位的排序,我們可以這樣排序:
但有時候我們的業務需求我們排序,但不以表中的字段排。而我們又不能沒有ORDER BY語句,我們應該怎么辦呢?是的,開發者也考慮到了:
select st_name,st_class,st_score,row_number() over(partition by st_class order by (select 0)) as '名次' from score_tab;當然,這并不是所有sql家族成員都是這么設計的,比如hive的方法就略有不同:
select st_name,st_class,st_score,row_number() over(partition by st_class order by 0) as '序值' from score_tab;直接用0,并不用select 0;
當然,這種排序也是有弊端的,就拿我們的學習成績為例,假如同一個窗口內的兩個同學分數相同,我們按這種方法排,可能他們一個是第二名,一個是第三名,這樣對孩子就太不公平了。于是,我們又有了另外兩種排序方式:
rank()和dense_rank()
三者的區別是:
2.數據均分分組函數–NTILE()
NTILE()的功能是進行均分分組,其參數是我們要分組的數量,比如,我們把學生平均分為四組,
select st_name,, st_class,,st_score,NTILE(4) OVER(ORDER BY st_score) as '分組' from score_tab;結果是按照成績排列為1,2,3,4組,部分數據如下:
| a | 1 | 68 | 1 |
| c | 4 | 69 | 1 |
| r | 3 | 72 | 1 |
| d | 4 | 85 | 1 |
如果我們按班級為單位,把每一個班的成績平均分為高、下兩種評級,則:
select st_name,, st_class,,st_score,CASE NTILE(2) OVER(PARTITION BY st_class ORDER BY st_score) when 1 then '低'when 1 then '高'END AS ‘level’ from score_tab;| p | 4 | 69 | 低 |
| g | 4 | 75 | 低 |
| e | 4 | 87 | 高 |
| j | 4 | 92 | 高 |
總結:
一般我們在使用排序函數的時候,我們不會同時使用distinct,因為我們在給記錄進行排序時,一般會忽略同值記錄,事實上我們執行如下語法,其中的distinct并沒有起作用,不會去重,只是增加了資源的開銷:
SELECT DISTINCT st_score,ROW_NUMBER() OVER(PARTITION BY st_class ORDER BY st_score) AS '排名' FROM score_tab;如果我們業務真實需要去重后再編序值,請用過濾條件GROUP BY,如:
SELECT st_score,ROW_NUMBER() OVER(PARTITION BY st_class ORDER BY st_score) AS '排名' FROM score_tab GROUP BY st_score;相關:替代方案–子查詢
在開窗函數沒有發布之前,我們進行窗口操作都是使用子查詢進行的,其原理為:先查出該組內比當前成績低的個數,再加上1,就是該學生在該組的序值,如:
select st_name,st_class,st_score--開窗函數方式,row_number() over(partition by st_class order by score) as '開窗序值名次'--子查詢(SELECT COUNT(1)+1 FORM st_score s2WHERE s2.st_class=a1.st_class AND s2.st_score<s1.st_score) as 子查詢名次 from score_tab s1;--如果是密集排序,我們只需把count()的參數改為排序字段即可去重,如 select st_name,st_class,st_score--開窗函數方式,row_number() over(partition by st_class order by score) as '開窗序值名次'--子查詢(SELECT COUNT(st_score)+1 FORM st_score s2WHERE s2.st_class=a1.st_class AND s2.st_score<s1.st_score) as 子查詢名次 from score_tab s1;總結
以上是生活随笔為你收集整理的开窗函数的意义与用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: _tcsnicmp_wcsnicmp
- 下一篇: WCHAR,CHAR,TCHAR的区别