SQL語句查詢連續(xù)N天登錄用戶(解決方案)
前幾天刷手機時看到一道有趣的 SQL 題:查詢連續(xù) 3 天登錄的用戶。這讓我聯(lián)想到之前討論過的開窗函數(shù),深入思考后發(fā)現(xiàn)其實還有多種實現(xiàn)方式。今天就來和大家分享幾種解決方案,歡迎一起討論!
一、建表:還原場景問題
1.創(chuàng)建用戶登錄記錄表t_login_records,包含用戶 ID 和登錄日期兩個核心字段
DROP TABLE IF EXISTS t_login_records;#若表存在刪除
-- 創(chuàng)建用戶登錄記錄表
CREATE TABLE t_login_records (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
login_date DATE NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='用戶登錄記錄表';2.插入測試數(shù)據(jù)
- 查看表結構
-- 查看表結構 DESC t_login_records;

- 數(shù)據(jù)預覽
INSERT INTO t_login_records (user_id, login_date) VALUES (1, '2023-01-01'), (1, '2023-01-02'), (1, '2023-01-03'), -- 用戶1連續(xù)3天登錄 (1, '2023-01-05'), (2, '2023-01-01'), (2, '2023-01-02'), (2, '2023-01-04'), -- 用戶2不連續(xù) (3, '2023-01-01'), (3, '2023-01-02'), (3, '2023-01-03'), -- 用戶3連續(xù)3天登錄 (3, '2023-01-04'), -- 用戶3連續(xù)4天登錄 (4, '2023-01-01'), (4, '2023-01-03'), (4, '2023-01-05'), -- 用戶4不連續(xù) (5, '2023-01-01'), (5, '2023-01-02'), (5, '2023-01-03'), -- 用戶5連續(xù)3天登錄 (5, '2023-01-04'), -- 用戶5連續(xù)4天登錄 (5, '2023-01-05'), -- 用戶5連續(xù)5天登錄 (5, '2023-02-01'), -- 斷開 (5, '2023-02-02'), -- 用戶5再連續(xù)2天登錄 (5, '2023-02-03'); -- 用戶5再連續(xù)3天登錄 SELECT * FROM t_login_records;

二、查詢:多種方法實現(xiàn)
1.自連接查詢
- 原理: 通過三次連接同一張表,強制匹配同一用戶的三條登錄記錄,且日期依此相差 1 天
-- 方法1:自連接查詢 SELECT DISTINCT t1.user_id FROM t_login_records t1 JOIN t_login_records t2 ON t1.user_id = t2.user_id AND DATEDIFF(t2.login_date, t1.login_date) = 1 JOIN t_login_records t3 ON t1.user_id = t3.user_id AND DATEDIFF(t3.login_date, t1.login_date) = 2;
- 查詢結果:
user_id為1、3、5的用戶

- 執(zhí)行步驟: 自連接將表t1(基準記錄)與t2(次日記錄)、t3(第三日記錄)連接,確保
- 用戶相同
t2.login_date=t1.login_date+1t3.login_date=t1.login_date+2DISTINCT過濾重復的user_id
- 示例數(shù)據(jù)驗證:
user_id=1的用戶在 2023-01-01、2023-01-02、2023-01-03 連續(xù)登錄:t1(2023-01-01)→t2(2023-01-02)→t3(2023-01-03),匹配成功。
user_id=2的用戶僅在 2023-01-01 和 2023-01-02連續(xù)登錄:- 無法找到連續(xù)三天的記錄,匹配失敗。

2.窗口函數(shù)
- 原理: 使用窗口函數(shù)
LEAD()獲取每個用戶后續(xù)的登錄日期,直接判斷是否連續(xù)。
-- 方法2:窗口函數(shù)(適用于支持LEAD函數(shù)的數(shù)據(jù)庫,如MySQL 8.0+、PostgreSQL)
SELECT DISTINCT user_id
FROM (
SELECT
user_id,
login_date,
LEAD(login_date, 1) OVER (PARTITION BY user_id ORDER BY login_date) AS next_day,
LEAD(login_date, 2) OVER (PARTITION BY user_id ORDER BY login_date) AS next_2_days
FROM t_login_records
) t
WHERE DATEDIFF(next_day, login_date) = 1
AND DATEDIFF(next_2_days, login_date) = 2;- 查詢結果:
user_id依然為1、3、5的用戶

- 執(zhí)行步驟: 窗口函數(shù)和條件過濾
LEAD(login_date, 1):獲取當前記錄的下一條日期。LEAD(login_date, 2):獲取當前記錄的下兩條日期。- 確保
next_day = login_date + 1且next_2_days = login_date + 2。
- 示例數(shù)據(jù)驗證:
- 用戶1的第一條記錄(2023-01-01):
- next_day=2023-01-02(差值1天)
- next_2_days=2023-01-03(差值2天)
- 滿足條件,用戶1被選中。
- 用戶4的第一條記錄(2023-01-01):
- next_day=2023-01-03
- next_2_days=2023-01-05
不滿足條件,用戶4未被選中。

3.日期差值分組
- 原理: 將每個登錄日期減去其在用戶組內的排序序號,連續(xù)日期會得到相同的差值,通過分組統(tǒng)計差值出現(xiàn)次數(shù)即可。
-- 方法3:日期差值分組(適用于支持ROW_NUMBER的數(shù)據(jù)庫)
SELECT user_id
FROM (
SELECT
user_id,
login_date,
DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) AS grp
FROM t_login_records
) t
GROUP BY user_id, grp
HAVING COUNT(DISTINCT login_date) >= 3;- 查詢結果:
user_id依然為1、3、5的用戶

- 執(zhí)行步驟:
計算分組標識grp和分組統(tǒng)計ROW_NUMBER()為每個用戶的登錄記錄分配連續(xù)序號(1,2,3…)。DATE_SUB(login_date,ROW_NUMBER()):將日期減去序號,連續(xù)日期會得到相同的結果。- 按
user_id和grp分組,統(tǒng)計每組的日期數(shù)量,若≥3則為連續(xù)登錄。

- DATE_SUB()函數(shù):
DATE_SUB(date, INTERVAL expr unit)是 SQL 中的一個日期函數(shù),用于從指定日期中減去一個時間間隔。INTERVAL expr unit:指定要減去的時間間隔INTERVAL:固定關鍵字,表示時間間隔expr是一個數(shù)值unit是時間單位(如 DAY、MONTH、YEAR 等)
三、總結:三種方法對比與拓展
| 方法 | 優(yōu)點 | 缺點 |
|---|---|---|
| 自連接 | 簡單直接,兼容性強 | 性能差(多次掃描表) |
| 窗口函數(shù) | 邏輯清晰,一步到位 | 需數(shù)據(jù)庫支持窗口函數(shù) |
| 日期差值 | 性能最優(yōu),邏輯巧妙 | 理解難度較高 |
這道題雖然僅要求查詢連續(xù) 3 天登錄的用戶,但通過這三種方法我們可以舉一反三。如果要查詢連續(xù) 4 天、5 天甚至 N 天登錄的用戶,第三種日期差值分組法更具優(yōu)勢,只需修改 HAVING COUNT(DISTINCT login_date) >= N 即可實現(xiàn) “一力破萬法” 的效果!
到此這篇關于SQL語句查詢連續(xù)N天登錄用戶的文章就介紹到這了,更多相關sql連續(xù)N天登錄用戶內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
sql?server修改數(shù)據(jù)庫文件位置的詳細步驟記錄
在SQL?Server中可以通過一系列的步驟來更改數(shù)據(jù)庫文件的存儲位置,這篇文章主要給大家介紹了關于sql?server修改數(shù)據(jù)庫文件位置的詳細步驟,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2024-07-07
SQL Server 監(jiān)控磁盤IO錯誤,msdb.dbo.suspect_pages
suspect_pages 表位于 msdb 數(shù)據(jù)庫中,是在 SQL Server 2005 中引入的。用于維護有關可疑頁的信息的 suspect_pages2014-10-10
sql server如何利用開窗函數(shù)over()進行分組統(tǒng)計
這篇文章主要介紹了sql server利用開窗函數(shù)over()進行分組統(tǒng)計的相關資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-03-03
sql server編寫通用腳本實現(xiàn)獲取一年前日期的方法
這篇文章主要介紹了sql server編寫通用腳本實現(xiàn)獲取一年前日期,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07
Windows環(huán)境下實現(xiàn)批量執(zhí)行Sql文件
這篇文章主要介紹了Windows環(huán)境下實現(xiàn)批量執(zhí)行Sql文件的相關資料,需要的朋友可以參考下2021-10-10

