橫掃SQL面試——連續性登錄問題

橫掃SQL面試

📌 連續性登錄問題

在這里插入圖片描述

在互聯網公司的SQL面試中,連續性問題堪稱“必考之王”。💻🔍

用戶連續登錄7天送優惠券🌟服務器連續報警3次觸發熔斷??圖書館連續3天人流破百開啟限流?” …

既考察你對窗口函數的靈活運用,又考驗你能否將業務場景抽象為數學模型。


博主總結一些經典題型,幫列位小伙伴拿下這類題目🤣 🤣 🤣 🤣


Tips:
暴力解法(如自連接、逐行遍歷)在數據量小時勉強可用,但面對百萬級📈數據時:

  • 性能災難:自連接時間復雜度達O(n2),1萬行數據需1億次計算 🔥
  • 邏輯漏洞:簡單lag/lead無法處理連續多天的復雜中斷

而真正的工業級解法,只需一行窗口函數 + 虛擬分組標記,就能以O(n)時間復雜度解決問題! 🚀

🌟 連續問題通用解法框架

步驟核心操作 🔑適用場景
生成連續標記date - row_number() over(...)映射連續日期到同一虛擬組
分組統計group by 虛擬組標記計算連續天數/次數
結果篩選having count(*) >= N過濾滿足條件的連續事件

話不多說——直接上題:🎈🎈🎈🎈🎈🎈🎈


🎯1. 最長連續登錄天數

你正在搭建一個用戶活躍度的畫像,其中一個與活躍度相關的特征是“最長連續登錄天數”

表名字段名描述數據類型
tb_daufdate登錄日期DATE
user_id用戶唯一標識INT

計算用戶在指定時間段內的最長連續登錄天數。例如:統計用戶2023年1月的最長連續登錄記錄。

fdateuser_id
2023-01-0110000
2023-01-0210000
2023-01-0410000

預期結果🔑

user_idmax_consec_days
100002

博主按照解題框架 一步一步帶大家看哈~🤣🤣🤣

步驟1:生成連續標記(CTE t1)🧩

為每個用戶的登錄日期生成序號,標記連續登錄的潛在分組。

with t1 as (selectuser_id,fdate,-- 默認大家都是有基礎的哈 窗口函數應該都會哈row_number() over(partition by user_id order by fdate) as rnfrom tb_dauwhere fdate between '2023-01-01' and '2023-01-31'
)

臨時表 t1:?

user_idfdatern
100002023-01-011
100002023-01-022
100002023-01-043

在這里插入圖片描述

  • rn 表示用戶按日期排序后的登錄次數序號。
  • 連續日期的 rn 差值等于日期差值(例如:2023-01-02 是第2次登錄,日期差為1天)。

步驟2:計算虛擬起始點(CTE t2)🧩

通過 date_sub(fdate, interval rn day) 將連續日期映射到同一虛擬起始點。

t2 as (selectuser_id,fdate,date_sub(fdate, interval rn day) as start_datefrom t1
)

臨時表 t2:?

user_idfdatestart_date
100002023-01-012022-12-31
100002023-01-022022-12-31
100002023-01-042023-01-01

在這里插入圖片描述

  • 連續日期的 start_date 相同(如1月1日和1月2日均映射到2022-12-31)。
  • 非連續日期的 start_date 不同(如1月4日映射到2023-01-01)。

步驟3:統計連續天數(CTE t3)🧩

按用戶和虛擬起始點分組,統計每組中的記錄數(即連續天數)。

t3 as (selectuser_id,start_date,count(*) as cntfrom t2group by user_id, start_date
)

臨時表 t3:?

user_idstart_datecnt
100002022-12-312
100002023-01-011

在這里插入圖片描述

  • cnt 表示每個虛擬起始點對應的連續登錄天數。
  • 用戶10000有兩個連續區間:2天和1天。

最終結果取每個用戶的最大連續天數。🧩
selectuser_id,max(cnt) as max_consec_days
from t3
group by user_id;

輸出結果:?

在這里插入圖片描述

user_idmax_consec_days
100002
技術本質🧩

通過 date_sub(fdate, interval rn day),將連續日期的差值抵消,映射到同一虛擬起始點:

  • 連續日期fdate - rn 恒定?(如 1月1日-1天=12月31日,1月2日-2天=12月31日)。
  • 非連續日期fdate - rn 不同(如1月4日-3天=1月1日)。

將連續性問題轉化為分組計數問題,時間復雜度僅為 O(n)。?

完整代碼 ~

-- 定義第一個公共表表達式 (CTE) t1,用于計算每個用戶登錄日期的排序
with t1 as (selectuser_id,  -- 用戶IDfdate,    -- 登錄日期row_number() over(partition by user_id order by fdate) as rn  -- 為每個用戶的登錄日期生成排序編號from tb_dauwhere fdate between '2023-01-01' and '2023-01-31'  -- 選擇指定日期范圍內的記錄
), -- 定義第二個公共表表達式 (CTE) t2,用于計算每個登錄日期的起始日期
t2 as (selectuser_id,  -- 用戶IDfdate,    -- 登錄日期date_sub(fdate, interval rn day) as start_date  -- 計算起始日期:將登錄日期減去排序編號天數from t1
), -- 定義第三個公共表表達式 (CTE) t3,用于計算每個用戶在相同起始日期下的連續登錄天數
t3 as (selectuser_id,  -- 用戶IDcount(*) as cnt  -- 計算連續登錄天數from t2group by user_id, start_date  -- 按用戶和起始日期分組
)-- 從 t3 表中選擇用戶ID和其最大連續登錄天數
selectuser_id,  -- 用戶IDmax(cnt) as max_consec_days  -- 最大連續登錄天數
from t3
group by user_id;  -- 按用戶ID分組

🎯2. 連續出現的數字

從數字序列中找出至少連續出現3次的數字。例如:[1, 1, 1, 2, 2, 3] 中,1 連續出現3次。

表名字段名描述數據類型
logsid記錄序號INT
num數字值INT
idnum
11
21
31
42
52
63
ConsecutiveNums
1

這題同理~連續性問題解法框架:
1.💡 標記連續性:使用 row_number() 生成序號。
2. 🔍生成虛擬組:通過差值(如 id - rn)抵消連續增量。
3. 🛠?分組統計:按虛擬組聚合,篩選滿足條件的結果。

步驟1:生成連續標記(CTE t1)🚀

為每個數字按 id 排序生成行號,標記連續出現的潛在分組。

with t1 as (selectnum,id,row_number() over(partition by num order by id) as rnfrom logs
)

臨時表 t1:?

numidrn
111
122
133
241
252
361

在這里插入圖片描述

  • rn 表示相同數字(num)按 id 排序后的出現次數序號。
  • 連續相同數字的 idrn 的差值恒定(例如:num=1 時,id - rn = 0)。

步驟2:計算虛擬分組標記(CTE t2)🚀

通過 id - rn 生成分組標記 group_id,將連續相同數字映射到同一虛擬組。

t2 as (selectnum,id - rn as group_idfrom t1
)

臨時表 t2:?

numgroup_id
10
10
10
23
23
35

在這里插入圖片描述

  • 連續相同數字的 group_id 相同(如 num=1 的3條記錄均為 group_id=0)。
  • 非連續或不同數字的 group_id 不同(如 num=2num=3)。

步驟3:統計連續出現次數(最終查詢)🚀

numgroup_id 分組,篩選出出現次數≥3的組,并去重輸出結果。

select distinct num as ConsecutiveNums
from t2
group by num, group_id
having count(*) >= 3;

分組統計結果:?

numgroup_idcount(*)
103
232
351

在這里插入圖片描述

最終輸出:?

ConsecutiveNums
1

技術本質🚀

通過 id - row_number(),將連續相同數字的差值抵消,映射到同一虛擬分組:

  • 連續相同數字id - rn 恒定🔥(如 num=1 時,id=1,2,31-1=0, 2-2=0, 3-3=0)。
  • 非連續或不同數字id - rn 不同(如 num=2 時,id=4,54-1=3, 5-2=3,但次數不足)。

如果題目要求連續出現4次,只需修改 having 條件:

having count(*) >= 4  -- 篩選連續出現4次的數字

🎯3. 新注冊用戶連續登錄不少于3天

篩選出新注冊用戶在注冊后至少連續登錄3天的用戶列表。例如:用戶注冊后連續登錄了2023-01-01、01-02、01-03三天。

表名字段名描述數據類型
tb_usersuser_id用戶唯一標識INT
reg_date用戶注冊日期DATE
tb_loginuser_id用戶唯一標識INT
login_date用戶登錄日期DATE

用戶表 (tb_users)?

user_idreg_date
100012023-01-01
100022023-01-05

登錄表 (tb_login)?

user_idlogin_date
100012023-01-01
100012023-01-02
100012023-01-03
100022023-01-05
100022023-01-06

預期結果

user_id
10001
步驟1:關聯用戶與登錄數據(CTE login_sequence)?

篩選注冊后7天內的登錄記錄,并為每個用戶的登錄日期生成行號。

with login_sequence as (selectu.user_id,l.login_date,-- 為每個用戶的登錄日期生成行號(按日期排序)row_number() over(partition by u.user_id order by l.login_date) as rnfrom tb_users ujoin tb_login l on u.user_id = l.user_idand l.login_date between u.reg_date and u.reg_date + interval 7 day
)

臨時表 login_sequence:?

user_idlogin_datern
100012023-01-011
100012023-01-022
100012023-01-033
100022023-01-051
100022023-01-062
  • rn 表示用戶按登錄日期排序后的連續次數。
  • login_date between reg_date and reg_date + 7 day 限定注冊后7天內的登錄行為。

限定用戶注冊后7天內的登錄行為,聚焦新用戶關鍵活躍期,數據進入窗口函數前剔除無效數據,避免對全量數據排序。聚焦核心業務目標(如新用戶激活率、首周留存率)


步驟2:生成虛擬分組標記(CTE consec_groups)🚀

計算 login_date - rn,將連續日期映射到同一虛擬起始點。

consec_groups as (selectuser_id,login_date,-- 計算虛擬分組標記(連續日期的差值為0)date_sub(login_date, interval rn day) as group_idfrom login_sequence
)

臨時表 consec_groups:?

user_idlogin_dategroup_id
100012023-01-012022-12-31
100012023-01-022022-12-31
100012023-01-032022-12-31
100022023-01-052023-01-04
100022023-01-062023-01-04
  • 連續登錄的日期差值相同(如用戶10001的3次登錄均映射到 2022-12-31)。🚀🚀🚀
  • 非連續登錄的日期差值不同(如用戶10002的2次登錄映射到 2023-01-04)。

步驟3:統計連續登錄天數(最終查詢)

按用戶和虛擬分組標記統計連續天數,篩選≥3天的用戶。

distinct user_id 確保用戶多次滿足條件時只輸出一次。

select distinct user_id
from consec_groups
group by user_id, group_id
having count(*) >= 3;

分組統計結果:?

user_idgroup_idcount(*)
100012022-12-313
100022023-01-042

最終輸出:?

user_id
10001

💡 關鍵邏輯

虛擬分組標記
date_sub(login_date, interval rn day) 將連續日期映射到同一虛擬起始點,本質是公式:
連續天數 = 最大登錄日期 - 最小登錄日期 + 1 (若連續,則 login_date - rn 恒定)


🎯4. 圖書館高峰期檢測

找出圖書館連續3天及以上人流量≥100的高峰時段。例如:2023-01-02至2023-01-04連續三天人流量達標。

表名字段名描述數據類型
infodate日期DATE
people人流量INT
datepeople
2023-01-0170
2023-01-02100
2023-01-03120
2023-01-04120
2023-01-0590

預期結果

start_dateend_dateconsecutive_days
2023-01-022023-01-043

后面博主就不再啰嗦啦 大家可以發現 套路是不是都一樣~🤣🤣🤣 “標記→分組→過濾”???

with valid_days as (select date,date - row_number() over(order by date) as grpfrom infowhere people >= 100
),
consec_groups as (selectmin(date) as start_date,max(date) as end_date,count(*) as consecutive_daysfrom valid_daysgroup by grphaving count(*) >= 3
)
select * from consec_groups;
  1. 篩選有效日期:過濾人流量≥100的天數。
  2. 生成連續組標記date - row_number() 將連續有效日期映射到同一組。
  3. 統計連續時段:按組統計起止日期和持續天數。

🎯5. 用戶指標檢測

從訂單表中篩選出連續三天及以上每天總下單金額均超過100元的用戶。例如:用戶A在2023-01-01至2023-01-03每天的總消費分別為120元、150元、110元,滿足條件。

表名字段名描述數據類型
order_tableid訂單編號INT
dt下單日期DATE
amount訂單金額INT
iddtamount
10012021-12-12123
10022021-12-1245
10012021-12-1343
10012021-12-1345
10012021-12-14230

預期結果

user_id
1001
-- 步驟1:按用戶和日期匯總金額,過濾每天金額>100的記錄
with daily_summary as (selectid as user_id,dt,sum(amount) as total_amountfrom order_tablegroup by user_id, dthaving sum(amount) > 100
),
-- 步驟2:生成連續標記
sequence_marker as (selectuser_id,dt,date_sub(dt, interval row_number() over(partition by user_id order by dt) day) as grpfrom daily_summary
),
-- 步驟3:統計連續天數
consec_groups as (selectuser_id,grp,count(*) as consec_days,min(dt) as start_date,max(dt) as end_datefrom sequence_markergroup by user_id, grphaving count(*) >= 3  -- 連續3天及以上
)
-- 步驟4:輸出結果
select distinct user_id
from consec_groups;
  1. 按天匯總金額group by user_id, dt 處理一天多筆訂單。
  2. 生成虛擬分組date_sub(dt, interval row_number() day) 將連續日期映射到同一虛擬組。
  3. 統計連續天數:篩選連續≥3天的用戶。

🎯6. 用戶最大連續繳費次數

計算每個用戶的最長連續繳費天數。例如:用戶U002在2023-01-03至2023-01-05連續繳費3天,結果為3。

表名字段名描述數據類型
payment_loguser_id用戶唯一標識VARCHAR
pay_date繳費日期DATE
amount繳費金額INT
user_idpay_dateamount
U0012023-01-01100
U0012023-01-02200
U0012023-01-04150
U0022023-01-0380
U0022023-01-0490
U0022023-01-05120

預期結果

user_idmax_consec_days
U0012
U0023

with payment_sequence as (selectuser_id,pay_date,date_sub(pay_date, interval row_number() over(partition by user_id order by pay_date) day) as grpfrom payment_log
),
consec_groups as (selectuser_id,grp,count(*) as consec_daysfrom payment_sequencegroup by user_id, grp
)
selectuser_id,max(consec_days) as max_consec_days
from consec_groups
group by user_id;
  1. 生成虛擬分組date_sub(pay_date, interval row_number() day) 標記連續繳費序列。
  2. 統計連續天數:按用戶和虛擬組計算連續繳費次數。
  3. 取最大值max(consec_days) 獲取每個用戶的最大連續天數。

🧩 連續性問題的通用解法框架

步驟核心操作適用場景
數據清洗按業務需求聚合數據(如按天匯總金額)處理多筆記錄/噪聲數據
生成連續標記date - row_number() 映射連續日期到虛擬組統一連續序列的時空標識
分組統計group by 虛擬組標記計算連續天數/次數
結果篩選havingmax() 過濾目標結果輸出滿足條件的用戶或時段

這一套組合拳下來??? 相信列位面試在遇到連續性登錄問題 絲毫不慌了😂


留個作業~ 有些難度哈——合并用戶停留位置

給定用戶位置停留記錄,需要對同一個用戶在同一個位置的連續多條記錄進行合并合并原則為開始時間取最早時間,停留時長加和。

表名字段名字段含義數據類型
用戶位置停留記錄表user用戶標識VARCHAR
location位置標識VARCHAR
start_time停留開始時間DATETIME
stay_duration停留的時長(分鐘)INT
userlocationstart_timestay_duration
UserALocationA2018-01-01 08:00:0060
UserALocationA2018-01-01 09:00:0060
UserALocationB2018-01-01 10:00:0060
UserALocationA2018-01-01 11:00:0060

結果預期:

userlocationstart_timestay_duration
UserALocationA2018-01-01 08:00:00120(08:00:00 開始的 60 分鐘和 09:00:00 開始的 60 分鐘合并)
UserALocationB2018-01-01 10:00:0060
UserALocationA2018-01-01 11:00:0060

很熟悉的套路啦

第一步:按照 用戶 、 地點 分組 起始時間 去排序。

在這里插入圖片描述

第二步:按照連續登錄問題 A列 - 排序列 做一個 分組標記

在這里插入圖片描述

第3步 分組之后 min sum聚合即可~

在這里插入圖片描述


后續還會繼續更新奧 求關注 求訂閱~🌟🌟🌟🌟

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/899743.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899743.shtml
英文地址,請注明出處:http://en.pswp.cn/news/899743.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring AI Alibaba 對話記憶使用

一、對話記憶 (ChatMemory)簡介 1、對話記憶介紹 ”大模型的對話記憶”這一概念,根植于人工智能與自然語言處理領域,特別是針對具有深度學習能力的大型語言模型而言,它指的是模型在與用戶進行交互式對話過程中,能夠追蹤、理解并利…

vdi模式是什么

?VDI模式(Virtual Desktop Infrastructure)是一種基于服務器的計算模型,其核心思想是將所有計算和存儲資源集中在服務器上,用戶通過前端設備(如瘦客戶機)訪問服務器上的虛擬桌面?? VDI模式的工作原理 在…

【分布式】深入剖析 Sentinel 限流:原理、實現

在當今分布式系統盛行的時代,流量的劇增給系統穩定性帶來了巨大挑戰。Sentinel 作為一款強大的流量控制組件,在保障系統平穩運行方面發揮著關鍵作用。本文將深入探討 Sentinel 限流的原理、實現方案以及其優缺點,助力開發者更好地運用這一工具…

c#winform,倒鴨子字幕效果,typemonkey字幕效果,抖音瀑布流字幕效果

不廢話 直接上效果圖 C# winform 開發抖音的瀑布流字幕。 也是typemonkey插件字幕效果 或者咱再網上常說的倒鴨子字幕效果 主要功能 1,軟件可以自定義添加字幕內容 2,軟件可以添加字幕顯示的時間區間 3,可以自定義字幕顏色,可以隨…

Pycharm(八):字符串切片

一、字符串分片介紹 對操作的對象截取其中一部分的操作,比如想要獲取字符串“888666qq.com前面的qq號的時候就可以用切片。 字符串、列表、元組都支持切片操作。 語法:字符串變量名 [起始:結束:步長] 口訣:切片其實很簡單,只顧頭來…

圖片解釋git的底層工作原理

(圖片來源:自己畫的) 基于同一個commit創建新分支 (圖片來源:書籍《Linux運維之道》 ISBN 9787121461811) 在新分支上修改然后commit一次 (圖片來源:書籍《Linux運維之道》 ISBN 978…

leetcode994.腐爛的橘子

思路源自 【力扣hot100】【LeetCode 994】腐爛的橘子|多源BFS 這里圖中的腐爛的的橘子是同時對周圍進行腐化,所以采用多源bfs就能解決 多源bfs與單源bfs的區別就在于隊列取出時一輪是取出隊列當中的全部元素 class Solution {public int orangesRotti…

【華為OD技術面試真題 - 技術面】- Java面試題(15)

華為OD面試真題精選 專欄:華為OD面試真題精選 目錄: 2024華為OD面試手撕代碼真題目錄以及八股文真題目錄 介紹下TCP/UDP TCP(傳輸控制協議)和 UDP(用戶數據報協議) TCP(Transmission Control Protocol)和 UDP(User Datagram Protocol)是兩種常見的傳輸層協議,主要…

?在 Fedora 系統下備份遠程 Windows SQL Server 數據庫的完整方案

?一、環境準備與工具安裝? ?1. 安裝 Microsoft SQL Server 命令行工具? Fedora 需安裝 mssql-tools 和 ODBC 驅動: # 添加 Microsoft 倉庫 sudo curl -o /etc/yum.repos.d/msprod.repo https://packages.microsoft.com/config/rhel/8/prod.repo# 安裝工具包 …

DeepSeek:巧用前沿AI技術,開啟智能未來新篇章

引言 近年來,人工智能(AI)技術迅猛發展,大模型成為全球科技競爭的核心賽道。在這場AI革命中,DeepSeek作為中國領先的大模型研發團隊,憑借其創新的技術架構、高效的訓練方法和廣泛的應用場景,迅…

R語言實現軌跡分析--traj和lcmm包體會

R語言實現軌跡分析–traj和lcmm包體會 軌跡分析是對重復測量數據的一種歸納,轉化為一種分類變量,比如手術后1~7天內的疼痛評分,可以形成術后急性痛軌跡。形成的軌跡作為一個分類變量,可以用于預測疾病的預后&#xff…

Vue 3 事件總線詳解:構建組件間高效通信的橋梁

Vue 3 事件總線詳解:構建組件間高效通信的橋梁 為什么需要事件總線?使用 mitt 實現事件總線1. 安裝 mitt2. 創建事件總線3. 在組件中使用事件總線發送端組件(例如 ComponentA.vue)接收端組件(例如 ComponentB.vue&…

MySQL的基礎語法1(增刪改查、DDL、DML、DQL和DCL)

目錄 一、基本介紹 二、SQL通用語法 三、SQL分類(DDL、DML、DQL、DCL) 1.DDL 1.1數據庫操作 1.2表操作 1.2.1表操作-查詢創建 1.2.2表操作-數據類型 1)數值類型 2)字符串類型 3)日期時間類型?編輯 4)表操作-案例 1.2.3…

【NLP】15. NLP推理方法詳解 --- 動態規劃:序列標注,語法解析,共同指代

動態規劃 (Dynamic Programming) 動態規劃(Dynamic Programming,簡稱 DP)是一種通過將問題分解為較小子問題來優化計算效率的技術。它特別適用于優化最優解問題,比如序列標注(sequence tagging)這類任務。…

JavaScript中的NaN、undefined和null 的區別

NaN代表"Not a Number",它是一種特殊的數值,用于表示非數字值。當一個操作無法返回有效的數值時,通常會得到NaN作為結果。 let result = 10 / abc; console.log(result); // 輸出 NaN需要注意的是,NaN與自身不相等,我們無法通過簡單的比較操作符(如==或===)來…

Turtle事件處理(鍵盤與鼠標交互)

Turtle 提供了 事件驅動編程,允許我們使用 鍵盤 和 鼠標 控制 Turtle,從而實現交互式繪圖。例如,我們可以讓 Turtle 響應 按鍵、鼠標點擊 和 拖動 事件,使其根據用戶的輸入進行移動、旋轉或繪制圖形。 1. 事件機制概述 Turtle 的事件處理主要依賴 turtle.Screen() 提供的 …

【Keepalived】Keepalived-2.3.3明確結束對CentOS 7的支持

2025年3月30日,官方發布了Keepalived的最新版,版本號:2.3.3 而2024年11月3日發布的2.3.2版本,在CentOS 7.9上編譯的時候,就出現了報錯,但是在Alma Linux 8.10上,則可以成功編譯安裝&#xff0c…

PyTorch --torch.cat張量拼接原理

在 PyTorch 的 torch.cat 函數中,out 參數用于指定輸出張量的存儲位置。是否使用 out 參數直接影響結果的存儲方式和張量的內存行為。以下是詳細解釋: 不使用 out 參數(默認行為) 含義:不提供 out 參數時,…

人工智能之數學基礎:矩陣對角化的本質

本文重點 前面的課程中,我們學習了矩陣的對角化,基于對角化可以將矩陣A轉變為對角矩陣D,但是你有沒有想過,為什么要進行矩陣對角化,矩陣對角化究竟做了一件什么事情呢? 矩陣對角化的本質 幾何解釋: 從幾何變換的角度看,矩陣對角化意味著我們找到了一組基,使得線性變…

ubuntu的ubuntu--vg-ubuntu--lv磁盤擴容

在我們安裝ubuntu時,如果選擇的是自動分區,就會按照邏輯卷的形式來分區,并且只分配100G其余的并不會被分配,這對我們大多數情況來說都是不合理的,所以,如何擴充呢 下面以一個小的案例來說明如何擴充 問題…