日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Sql如何统计连续打卡天数

發(fā)布時(shí)間:2023/12/19 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Sql如何统计连续打卡天数 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

總第208篇/張俊紅

今天來解一道題面試中可能經(jīng)常會(huì)被一些面試官拿來“刁難”的題,就是《如何統(tǒng)計(jì)連續(xù)打卡天數(shù)》,當(dāng)然了這里面的打卡可以換成任意其他行為,比如連續(xù)登陸天數(shù),連續(xù)學(xué)習(xí)天數(shù),連續(xù)購買天數(shù),這里的天數(shù)也是可以換成小時(shí)或者別的時(shí)間單位的。這個(gè)問題的邏輯還是有點(diǎn)復(fù)雜,如果要是之前沒遇到過這種問題,當(dāng)場(chǎng)被問到的時(shí)候,肯定會(huì)一臉懵。

直接來看實(shí)戰(zhàn),現(xiàn)在有一張表t,這張表存儲(chǔ)了每個(gè)員工每天的打卡情況,現(xiàn)在需要統(tǒng)計(jì)截止目前每個(gè)員工的連續(xù)打卡天數(shù),表t如下表所示:

uidtdateis_flag
12020/2/11
12020/2/20
12020/2/31
12020/2/41
12020/2/50
12020/2/61
12020/2/71
12020/2/81
22020/2/11
22020/2/20
22020/2/30
22020/2/41
22020/2/51
22020/2/61
22020/2/71
22020/2/81

上表中uid是用戶id,tdate是日期,is_flag是記錄用戶當(dāng)天是否打卡,1為打卡,0為未打卡。

我們希望得到的結(jié)果為:

uidflag_days
13
25

這個(gè)邏輯還是挺難想的,第一個(gè)想法就是通過前后數(shù)據(jù)偏移來實(shí)現(xiàn),就是將is_flag向前移動(dòng)一行或者向后移動(dòng)一行,然后和原來的is_flag標(biāo)簽做差,如果結(jié)果為0,說明前后兩天的值是相同的,要么都是0,要么都是1。但是還是不能夠得出我們想要的結(jié)果。

再換一種思路:如果是連續(xù)打卡,那么打卡日期與一個(gè)遞增的數(shù)字依次做差的結(jié)果值應(yīng)該是相等的,不理解這句話沒關(guān)系,看具體結(jié)果你就明白了。

我們先獲取每個(gè)用戶在這一段時(shí)間內(nèi)所有打卡的排名,是所有打卡的排名哦,利用的是窗口函數(shù)的row_number(),代碼如下:

select??uid,tdate,row_number()?over(partition?by?uid?order?by?tdate)?date_rank fromt where?is_flag=1

運(yùn)行上面的代碼,可以得到如下結(jié)果:

uidtdatedate_rank
12020/2/11
12020/2/32
12020/2/43
12020/2/64
12020/2/75
12020/2/86
22020/2/11
22020/2/42
22020/2/53
22020/2/64
22020/2/75
22020/2/86

接著再獲取每個(gè)打卡日期(tdate)中的日與其打卡日期排名(date_rank)之間的差,比如uid=1的2020/2/3的打卡日期中的3號(hào)與其排名(date_rank)2做差等于1,實(shí)現(xiàn)代碼如下:

select?uid,tdate,date_rank,(date_format(tdate,"%e")?-?date_rank)?as?day_cha from?(select??uid,tdate,row_number()?over(partition?by?uid?order?by?tdate)?date_rankfromdemo.newtablewhere?is_flag=1)t1

運(yùn)行上面的代碼,最后可以得到如下結(jié)果:

uidtdatedate_rankday_cha
12020/2/110
12020/2/321
12020/2/431
12020/2/642
12020/2/752
12020/2/862
22020/2/110
22020/2/422
22020/2/532
22020/2/642
22020/2/752
22020/2/862

看上面的結(jié)果表,有沒有看出點(diǎn)意思來,連續(xù)打卡日期的day_cha都是相等的,比如uid=1的2020/2/3和2020/2/4是連續(xù)的,他們的day_cha都是1。到這里,如果我們要獲取連續(xù)打卡天數(shù)是不是就很容易了。

不過這里面還有一個(gè)問題,就是連續(xù)打卡天數(shù)是截止目前最近的一個(gè) 連續(xù)打卡天數(shù)還是歷史堅(jiān)持最長的打卡天數(shù),這就是傳說中的口徑問題哈。雖然在我們這個(gè)例子里面,這兩種打卡天數(shù)的出來的結(jié)果是一樣的,但是有的時(shí)候會(huì)是不一樣的,比如下面這樣的例子:

uidtdateis_flag
12020/2/11
12020/2/20
12020/2/31
12020/2/41
12020/2/51
12020/2/60
12020/2/71
12020/2/81

上面這個(gè)例子中,最近連續(xù)打卡天數(shù)是2,歷史最長的連續(xù)打卡天數(shù)卻是3。

好了,我們繼續(xù)回到解題上,我們先獲取每個(gè)用戶歷史所有連續(xù)過得的打卡情況,實(shí)現(xiàn)代碼如下:

select?uid,day_cha,count(tdate)?flag_days from?(select?uid,tdate,date_rank,(date_format(tdate,"%e")?-?date_rank)?as?day_cha from?(select??uid,tdate,row_number()?over(partition?by?uid?order?by?tdate)?date_rankfromdemo.newtablewhere?is_flag=1)t1)t2 group?by?uid,day_cha

運(yùn)行上面的代碼,得到如下結(jié)果:

uidday_chaflag_days
101
112
123
201
225

要獲取最近的連續(xù)打卡天數(shù),我們只需要把上表中day_cha這一列最大的值對(duì)應(yīng)的flag_days取出來就可以;要獲取歷史最久的連續(xù)打卡天數(shù),我們只需要把上表中flag_days的最大值取出來就可以。直接再來個(gè)子查詢就好了。

類似的需求可能還有獲取過去連續(xù)打卡天數(shù)大于某個(gè)值得人,只需要篩選上表中的flag_days即可達(dá)到目的。只要能夠生成上面這樣每個(gè)人歷史所有連續(xù)打卡的情況表,那么大部分連續(xù)打卡相關(guān)的需求都可以通過上表來獲得。

很經(jīng)典的一道題,或者是一種業(yè)務(wù)場(chǎng)景,大家各自多多練習(xí)。

你還可以看:

講講你不知道的窗口函數(shù)

總結(jié)

以上是生活随笔為你收集整理的Sql如何统计连续打卡天数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。