一文讲透窗口函数
01|什么是窗口函數(shù)
我們都知道 SQL 中的聚合函數(shù),聚合函數(shù)顧名思義就是聚集合并的意思,是對(duì)某個(gè)范圍內(nèi)的數(shù)值進(jìn)行聚合,聚合后的結(jié)果是一個(gè)值或是各個(gè)類別對(duì)應(yīng)的值。如下所示:
直接聚合得到的結(jié)果是所有店鋪在這段時(shí)間內(nèi)的所有銷量之和,分組聚合(group by)得到的結(jié)果是每個(gè)店鋪在這段時(shí)間內(nèi)的銷量之和。
這種聚合函數(shù)得到的數(shù)據(jù)行數(shù)是小于基礎(chǔ)數(shù)據(jù)行數(shù)的,但是我們經(jīng)常會(huì)有這樣的需求,就是既希望看基礎(chǔ)數(shù)據(jù)同時(shí)也希望查看聚合后的數(shù)據(jù),這個(gè)時(shí)候聚合函數(shù)就滿足不了我們了,窗口函數(shù)就派上用場(chǎng)了。窗口函數(shù)就是既可以顯示原始基礎(chǔ)數(shù)據(jù)也可以顯示聚合數(shù)據(jù)。可能你還是不太理解,沒(méi)關(guān)系,我也剛開(kāi)始不太理解,我們看幾個(gè)關(guān)于窗口函數(shù)的具體的應(yīng)用就理解了。
02|聚合函數(shù)+over()
現(xiàn)在有如下的一張表 t 存儲(chǔ)了每個(gè)店鋪每天的銷量:
shopname??sales??date?????? A?????????1??????2018/4/1?? B?????????3??????2018/4/1?? C?????????5??????2018/4/1?? A?????????7??????2018/4/2?? B?????????9??????2018/4/2?? C?????????2??????2018/4/2?? A?????????4??????2018/4/3?? B?????????6??????2018/4/3?? C?????????8??????2018/4/3?如果我們想看一下每個(gè)店鋪每天的銷量和一段時(shí)間內(nèi)所有店鋪銷量的平均值的話該怎么做呢?答案就是可以用窗口函數(shù)來(lái)實(shí)現(xiàn)。只需要除了基礎(chǔ)的查詢代碼以外,還需要在你要聚合的字段后面加一個(gè) over(),語(yǔ)句如下所示:
selectshopname,sales,date,avg(sales)?over() fromt最后結(jié)果如下所示:
shopname??sales??date??????avg_window_0 A?????????1??????2018/4/1??5 B?????????3??????2018/4/1??5 C?????????5??????2018/4/1??5 A?????????7??????2018/4/2??5 B?????????9??????2018/4/2??5 C?????????2??????2018/4/2??5 A?????????4??????2018/4/3??5 B?????????6??????2018/4/3??5 C?????????8??????2018/4/3??502|partition by子句
再想象一下,上面我們是拿每個(gè)店鋪每天的銷量和全部店鋪全部天數(shù)的平均銷量作比較,如果我們現(xiàn)在想讓每個(gè)店鋪每天的銷量與自身全部天數(shù)的平均值作比較,該怎么實(shí)現(xiàn)呢?答案就是使用 partition by ,partition by的作用和 group by 是類似的,是進(jìn)行分組聚合的,需要與 over() 搭配使用。
selectshopname,sales,date,avg(sales)?over(partition?by?shopname) fromt最后結(jié)果如下所示:
shopname??sales??date??????avg_window_0 A?????????1??????2018/4/1??4 B?????????3??????2018/4/1??6 C?????????5??????2018/4/1??5 A?????????7??????2018/4/2??4 B?????????9??????2018/4/2??6 C?????????2??????2018/4/2??5 A?????????4??????2018/4/3??4 B?????????6??????2018/4/3??6 C?????????8??????2018/4/3??503|order by子句
order by 就是按照某一列數(shù)值進(jìn)行排序,主要與接下來(lái)的序列函數(shù)結(jié)合使用,當(dāng) order by 與聚合函數(shù)一起使用時(shí),是順序聚合的。什么叫順序聚合呢?給大家舉一個(gè)求和的聚合與 order by 結(jié)合使用的例子,就是類似于累計(jì)和的效果,具體代碼如下:
selectshopname,sales,date,sum(sales)?over(partition?by?shopname?order?by?date) fromt最后運(yùn)行結(jié)果如下:
shopname??sales??date??????sum_window_0 A?????????1??????2018/4/1??1 A?????????7??????2018/4/2??8 A?????????4??????2018/4/3??12 B?????????3??????2018/4/1??3 B?????????9??????2018/4/2??12 B?????????6??????2018/4/3??18 C?????????5??????2018/4/1??5 C?????????2??????2018/4/2??7 C?????????8??????2018/4/3??15當(dāng) order by 與序列函數(shù)一起使用時(shí)就是用于排序。
04|序列函數(shù)
什么是序列函數(shù),就是可以將數(shù)據(jù)整理成一個(gè)有序的序列,然后我們可以在這個(gè)序列里面挑選我們想要的序列對(duì)應(yīng)的數(shù)據(jù)。
4.1 ntile
ntile 函數(shù)主要是用于將整表數(shù)據(jù)進(jìn)行切片分組,默認(rèn)是對(duì)表在不做任何操作之前進(jìn)行切片分組的,比如現(xiàn)在整個(gè)表有9行數(shù)據(jù),你要切片分成3組,那么就是第 1-3 行為一組,4-6 行為一組,7-9 行為一組。我們將店鋪銷量表切分成3組,代碼如下:
selectshopname,date,sales,ntile(3)?over() fromt最后結(jié)果如下:
shopname??sales??date??????ntile_window_0 A?????????1??????2018/4/1??1 B?????????3??????2018/4/1??1 C?????????5??????2018/4/1??1 A?????????7??????2018/4/2??2 B?????????9??????2018/4/2??2 C?????????2??????2018/4/2??2 A?????????4??????2018/4/3??3 B?????????6??????2018/4/3??3 C?????????8??????2018/4/3??3上面是把銷量表切分成3組了,但是對(duì)我們實(shí)際應(yīng)用中沒(méi)什么實(shí)際作用啊,你想一下,你拿一個(gè)亂序分組有什么用?如果我們和 order by結(jié)合使用就有用了,比如我先按照 sales 升序排列,然后再進(jìn)行切片分組,這個(gè)時(shí)候的切片就有意義了。也可以在分組內(nèi)(partition by)近行切片分組,示例如下:
selectshopname,date,sales,ntile(3)?over(partition?by?shopname?order?by?sales) fromt最后結(jié)果如下:
shopname??sales??date??????ntile_window_0 A?????????1??????2018/4/1??1 A?????????4??????2018/4/3??2 A?????????7??????2018/4/2??3 B?????????3??????2018/4/1??1 B?????????6??????2018/4/3??2 B?????????9??????2018/4/2??3 C?????????2??????2018/4/2??1 C?????????5??????2018/4/1??2 C?????????8??????2018/4/3??34.2 row_number
row_number() 從 1 開(kāi)始,按照順序(注意這里是順序不是排序)生成該條數(shù)據(jù)在分組內(nèi)的對(duì)應(yīng)的序列數(shù),row_number() 的值不會(huì)存在重復(fù),當(dāng)排序的值相同時(shí),按照表中記錄的順序進(jìn)行排列。
因?yàn)?row_number() 是按照順序生成對(duì)應(yīng)的序列,而不是按照排序來(lái)生成序列的,所以 row_number() 一般需要與 order by 進(jìn)行結(jié)合使用。
你現(xiàn)在想看一下,在一段時(shí)間內(nèi)每個(gè)店鋪 sales 對(duì)應(yīng)最早的一次 date 是什么時(shí)候?該怎么看呢?這個(gè)時(shí)候就可用 row_number() 與 order by 相結(jié)合,代碼如下:
selectshopname,date,sales,row_number()?over(partition?by?shopname?order?by?date) fromt因?yàn)槲覀兪且榭疵總€(gè)店鋪?zhàn)钤绲囊淮?date,所以需要對(duì) date 進(jìn)行升序排列。最后結(jié)果如下:
shopname??sales??date??????row_number_window_0 A?????????1??????2018/4/1??1 A?????????7??????2018/4/2??2 A?????????4??????2018/4/3??3 B?????????3??????2018/4/1??1 B?????????9??????2018/4/2??2 B?????????6??????2018/4/3??3 C?????????5??????2018/4/1??1 C?????????2??????2018/4/2??2 C?????????8??????2018/4/3??3我們只需要把 num = 1 的部分取出來(lái)就是我們想要的結(jié)果。
4.3 lag和lead
lag 的英文意思是滯后,而 lead 的英文意思是超前。對(duì)應(yīng)的 lag 是讓數(shù)據(jù)向后移動(dòng),而 lead 是讓數(shù)據(jù)向前移動(dòng)。你可能不太理解,無(wú)所謂,直接來(lái)看實(shí)例。
現(xiàn)在你想看一下每個(gè)店鋪這一次和上一次 date 的時(shí)間差,你該怎么看呢?可以借助 lag,代碼如下:
selectshopname,date,sales,lag(date,1)?over(partition?by?shopname?order?by?date) fromt最后結(jié)果如下:
shopname??sales??date??????lag_window_0 A?????????1??????2018/4/1??NULL A?????????7??????2018/4/2??2018/4/1 A?????????4??????2018/4/3??2018/4/2 B?????????3??????2018/4/1??NULL B?????????9??????2018/4/2??2018/4/1 B?????????6??????2018/4/3??2018/4/2 C?????????5??????2018/4/1??NULL C?????????2??????2018/4/2??2018/4/1 C?????????8??????2018/4/3??2018/4/2現(xiàn)在你想看一下每個(gè)店鋪這次和下一次 date 之間的時(shí)間差,你又該怎么看呢?可以借助 lead,代碼如下:
selectshopname,date,sales,lead(date,1)?over(partition?by?shopname?order?by?date) fromt最后結(jié)果如下:
shopname??sales??date??????lead_window_0 A?????????1??????2018/4/1??2018/4/2 A?????????7??????2018/4/2??2018/4/3 A?????????4??????2018/4/3??NULL B?????????3??????2018/4/1??2018/4/2 B?????????9??????2018/4/2??2018/4/3 B?????????6??????2018/4/3??NULL C?????????5??????2018/4/1??2018/4/2 C?????????2??????2018/4/2??2018/4/1 C?????????8??????2018/4/3??2018/4/34.4 first_value和last_value
first_value 和 last_value 都是顧名思義,就是獲取第一個(gè)值和最后一個(gè)值。但是不是真正意義上的第一個(gè)或最后一個(gè),而是截至到當(dāng)前行的第一個(gè)或最后一個(gè)。
現(xiàn)在你想看一下每個(gè)店鋪的首次 date 和最后一次 date,你會(huì)怎么看呢?就可以直接借助first_value 和 last_value,代碼如下:
selectshopname,date,sales,first_value(date)?over(partition?by?shopname?order?by?date),last_value(date)?over(partition?by?shopname?order?by?date) fromt最后結(jié)果如下:
shopname??sales??date??????first_value_window_0???last_value_window_0 A?????????1??????2018/4/1??2018/4/1???????????????2018/4/1 A?????????7??????2018/4/2??2018/4/1???????????????2018/4/2 A?????????4??????2018/4/3??2018/4/1???????????????2018/4/3 B?????????3??????2018/4/1??2018/4/1???????????????2018/4/1 B?????????9??????2018/4/2??2018/4/1???????????????2018/4/2 B?????????6??????2018/4/3??2018/4/1???????????????2018/4/3 C?????????5??????2018/4/1??2018/4/1???????????????2018/4/1 C?????????2??????2018/4/2??2018/4/1???????????????2018/4/2 C?????????8??????2018/4/3??2018/4/1???????????????2018/4/3點(diǎn)分享
點(diǎn)收藏
點(diǎn)點(diǎn)贊
點(diǎn)在看
總結(jié)
- 上一篇: 菜鸟裹裹怎么设置拒绝放驿站
- 下一篇: 9999 元,小米游戏电视 ES Pro