書接上回,最近離職在家了實在無聊,除了看看考研的書,打打dnf手遊,也就只能寫寫程式碼,結果昨晚掛在某平臺的一個技術出售有人下單了,大概業務是需要幫忙輔導一些面試需要用到的SQL。
回想了下,在該平臺接單SQL也超過3w元了,考察的也就是那幾大類,我準備開一個新的專題,把我遇到的題目做一些示例和總結,歡迎大家指正。
今日主題:連續資料的查詢
場景
場景一:需要查詢最大連續簽到的時長,一般用於toc的場景中
場景二:查詢連續人流量超過2w的日期,某遊樂場的業務管理系統
思路
這種題目我一般常用的思路就是動轉靜,連續轉不變。
比如場景二,需要找連續的日期,那麼就要再找一個連續的變數,讓兩個變數進行相減或者其他操作,得到不變的資料,然後透過分組或者分割槽查詢即可。
例題
體育館人流量表
列名 | 型別 |
---|---|
id | int |
visit_date | date |
people | int |
visit_date 是該表中具有唯一值的列。
每日人流量資訊被記錄在這三列資訊中:序號 (id)、日期 (visit_date)、 人流量 (people)
每天只有一行記錄,id與日期遞增,日期不一定是連續遞增。
編寫SQL找出每天的人數大於或等於 100 且 日期 連續的三行或更多行記錄。返回按 visit_date 升序排列 的結果表
Scheme:
Create table If Not Exists Stadium (id int, visit_date DATE NULL, people int)
Truncate table Stadium
insert into Stadium (id, visit_date, people) values ('1', '2017-01-01', 10)
insert into Stadium (id, visit_date, people) values ('2', '2017-01-02', 109)
insert into Stadium (id, visit_date, people) values ('3', '2017-01-03', 150)
insert into Stadium (id, visit_date, people) values ('4', '2017-01-04', 99)
insert into Stadium (id, visit_date, people) values ('5', '2017-01-05', 145)
insert into Stadium (id, visit_date, people) values ('6', '2017-01-06', 1455)
insert into Stadium (id, visit_date, people) values ('7', '2017-01-07', 199)
insert into Stadium (id, visit_date, people) values ('8', '2017-01-09', 188)
例題解釋
體育館的人流表,要求找出最少三天連續人流量超過100的資料,並且按照
visit_date升序排序。
實戰
做題目前先回顧下SqlServer中的一個函式
DATEADD(DAY,2,'2020-03-27');
該函式可以在日期上進行加減,並且可以執行加減的日期部分,DAY表示天數增加。
按照思路,日期連續,那麼可以生成一列行號,用日期與行號作差,如果結果相等則表示連續。
解題 生成行號
需要自己創造動態列,比如自己新增行號列
至於為什麼不用ID,id也是遞增的,我們做完再講。
SELECT t1.id,t1.visit_date,t1.people FROM (
SELECT t.*, COUNT(1) OVER(partition by DATEADD(DAY, t.rowId * -1,t.visit_date)) AS daysCount FROM
(SELECT *,ROW_NUMBER() Over (ORDER BY id) as rowId FROM Stadium where people >= 100) t
) t1 WHERE t1.daysCount > =3
步驟
1.篩選人流量大於等於100的資料,並且透過分割槽函式增加行號
2.用日期減去行號得到一個日期,相等則表示日期連續,再次透過分割槽函式基於得到的日期獲取分割槽數量
3.篩選分割槽數量大於等於3的就是連續三天或者三天以上人流量大於等於100的資料
4.作為子查詢結果處理得到結果。
結果
為什麼不用id還是需要自己創造行號。因為篩選掉人流量不夠的資料後,id與時間的等差結果還是不會變,就會得到錯誤的資料,本身不滿足的資料仍舊會被查詢出來。