sql去掉日期橫槓 SQL 獲取最長的序列

2021-10-18 00:04:46 字數 3663 閱讀 9632

有一張學習打卡表his_sign表,簡單起見,只設定了兩個字段(id,create_ts),乙個是主鍵,另乙個是打卡時間。his_sign表的資料如下,我們要統計出這張表裡面最長的連續打卡記錄。

id            create_ts  

------ ---------------------

1 2020-05-01 09:04:26

2 2020-05-02 11:54:45

3 2020-05-04 23:05:03

4 2020-05-06 07:12:31

5 2020-05-06 08:01:52

6 2020-05-07 22:06:48

7 2020-05-08 12:36:58

8 2020-05-09 11:49:13

9 2020-05-12 08:52:35

10 2020-05-13 23:45:57

11 2020-05-14 00:02:24

12 2020-05-14 09:24:18

13 2020-05-19 15:34:45

14 2020-05-21 21:10:02

先檢查資料,我們發現在一天之內可以多次打卡,因此需要先去掉重複打卡的記錄,並將字段create_ts使用日期格式展示。

select distinct 

(date(create_ts)) as create_ts

from

his_sign

去重並格式化後的資料如下:

create_ts   

------------

2020-05-01

2020-05-02

2020-05-04

2020-05-06

2020-05-07

2020-05-08

2020-05-09

2020-05-12

2020-05-13

2020-05-14

2020-05-19

2020-05-21

由於資料量不大,我們觀察表資料可知,2020-05-062020-05-09是最長的序列,總共 4 天。

解題的思路就是把連續的日期編為一組,然後從多組資料中找到數量最多的一組資料,那組資料就是最長的序列。

將表裡面的資料按日期的公升序排序,並給每個日期分配乙個連續的自然數序號,用日期減去它對應的序號,會得到乙個新的日期值。我們發現,連續的日期它們對應的新的日期值為同乙個,因此,這個新的日期值就是序列的組別。

找到連續日期的組的 sql 如下:

with t1 as 

(select distinct

(date(create_ts)) as create_ts

from

his_sign),

t2 as

(select

create_ts,

row_number () over (

order by create_ts) as rn

from

t1)

select

create_ts,

date_sub(create_ts, interval rn day) as grp

from

t2

上面 sql 執行後輸出的結果:

create_ts   grp         

---------- ------------

2020-05-01 2020-04-30

2020-05-02 2020-04-30

2020-05-04 2020-05-01

2020-05-06 2020-05-02

2020-05-07 2020-05-02

2020-05-08 2020-05-02

2020-05-09 2020-05-02

2020-05-12 2020-05-04

2020-05-13 2020-05-04

2020-05-14 2020-05-04

2020-05-19 2020-05-08

2020-05-21 2020-05-09

剩下的操作就簡單多了,把資料最多的那組找出來就對了。只是需要注意,最長的序列有可能有多個,因此在找最長的序列的時候需要注意方法。

結合開窗函式rank() over(order by ***)可以找到多個最長序列,完整的 sql 如下:

# 1.去掉重複日期,並格式化

with t1 as

(select distinct

(date(create_ts)) as create_ts

from

his_sign),

# 2.給每個日期指定乙個序號

t2 as

(select

create_ts,

row_number () over (

order by create_ts) as rn

from

t1),

# 3.找到分組的依據

t3 as

(select

create_ts,

date_sub(create_ts, interval rn day) as grp

from

t2),

# 4.分組

t4 as

(select

min(create_ts) as start_date,

max(create_ts) as end_date,

count(*) as cnt

from

t3 group by grp),

# 5.對所有序列按照長度降序排序

t5 as

(select

*,rank () over (

order by cnt desc) as rk

from

t4)

# 6.只選擇最長的序列

select

start_date,

end_date,

cnt

from

t5 where rk = 1

輸出:

start_date  end_date       cnt  

---------- ---------- --------

2020-05-06 2020-05-09 4

為了讓大家看得更明白,我用 cte 表示式把每個過程都寫出來了。每段表示式都加了注釋,理解起來應該不難。

注意,上述的 sql 需要在 mysql 8.0 + 環境裡才能正常執行。

sql獲取日期

declare aa varchar 20 set aa convert varchar 100 getdate 23 日 print aa 0 00 00.000 print aa 23 59 59.999 周 print convert varchar 100 dateadd wk,datedi...

SQL當前日期獲取技巧

當前日期 select convert varchar 10 getdate 120 乙個月第一天的sql 指令碼 select dateadd mm,datediff mm,0,getdate 0 本週的星期一 select dateadd wk,datediff wk,0,getdate 0 一...

SQL當前日期獲取技巧

當前日期 select convert varchar 10 getdate 120 乙個月第一天的sql 指令碼 select dateadd mm,datediff mm,0,getdate 0 本週的星期一 select dateadd wk,datediff wk,0,getdate 0 一...