news 2026/6/3 16:08:50

深度解析 SQL 经典面试题:如何优雅地计算连续登录天数?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深度解析 SQL 经典面试题:如何优雅地计算连续登录天数?

问题描述:

数据表字段:user_id,login_date,一天多次登录只算当天登录一次。

问题需求1:

统计每个用户的总登陆天数

SELECT user_id, COUNT(DISTINCT login_date) AS total_login_days FROM your_table_name -- 替换成你实际的表名 GROUP BY user_id;

问题需求2:

统计每个用户的连续登陆天数

思路:

假设有个用户连续三天登录:

  • 1号(序号是1):用 1号 减去 1天,结果是0号
  • 2号(序号是2):用 2号 减去 2天,结果还是0号
  • 3号(序号是3):用 3号 减去 3天,结果依然是0号

你看,只要是连续的,算出来的结果(也就是那个“差值”)永远都是同一个数(比如都是0号)。

那如果中间断了一天呢?比如跳到了5号:

  • 5号(序号变成了4):用 5号 减去 4天,结果就变成了1号

结果从“0号”变成了“1号”,不一样了!这就说明中间断开了,属于新的一段连续登录。

简单总结一下就是:
我们在 SQL 里算出这个“差值”,然后按这个差值分组。只要差值一样,就说明这几天是连着的;差值变了,就说明中间断过。

这样解释是不是清楚多啦?😄

💡 代码逻辑拆解

  1. 去重 (DISTINCT):先把同一天内的多次登录合并成一条,避免干扰后续的序号排列。
  2. 打标 (ROW_NUMBER+DATE_SUB)
    • ROW_NUMBER()会为每个用户的登录记录按时间先后生成 1, 2, 3... 的序号。
    • 假设某用户连续在01-01,01-02,01-03登录,序号分别是 1, 2, 3。
    • 用日期减去序号(01-01减 1天 =12-3101-02减 2天 =12-31...),你会发现算出来的grp都是同一天(12-31)。这个grp就是该段连续登录的“唯一锚点”。
  3. 分组统计 (GROUP BY):只要grp相同,就说明它们在同一段连续登录区间里。直接按user_idgrp分组,COUNT(*)就能算出这段连续了多少天。
  4. 筛选 (HAVING):最后可以根据业务需求,比如筛选出COUNT(*) >= 3的“忠实用户”。
SELECT user_id, MIN(login_date) AS start_date, -- 这段连续登录的开始日期 MAX(login_date) AS end_date, -- 这段连续登录的结束日期 COUNT(*) AS consecutive_days -- 连续登录的天数 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 ( -- 第一步:数据去重(同一天多次登录只保留一条) SELECT DISTINCT user_id, login_date FROM user_login ) t1 ) t2 GROUP BY user_id, grp -- 第三步:按用户和差值日期分组 HAVING COUNT(*) >= 3; -- 第四步:筛选(比如找出连续登录3天及以上的记录)

问题需求3:

统计每个用户的最长连续登陆天数

如果你不需要列出每一段连续记录,只想知道每个用户历史上最长连续登了多少天,只需要在上面的基础上再套一层MAX聚合:

SELECT user_id, MAX(consecutive_days) AS max_consecutive_days -- 取出该用户所有连续段中的最大值 FROM ( SELECT user_id, COUNT(*) AS consecutive_days FROM ( SELECT user_id, DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) AS grp FROM ( SELECT DISTINCT user_id, login_date FROM user_login ) t1 ) t2 GROUP BY user_id, grp ) t3 GROUP BY user_id;

问题需求4:

想看“连续登录天数最长”的用户

SELECT user_id, MAX(consecutive_days) AS max_consecutive_days -- 算出每个用户的最长连续天数 FROM ( SELECT user_id, COUNT(*) AS consecutive_days FROM ( SELECT user_id, -- 核心:日期减去序号,得出连续分组的基准日期 DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) AS grp FROM ( SELECT DISTINCT user_id, login_date FROM user_login ) t1 ) t2 GROUP BY user_id, grp ) t3 GROUP BY user_id ORDER BY max_consecutive_days DESC -- 按最长天数降序排列 LIMIT 1; -- 只取第1名(如果想看前10名,就改成 LIMIT 10)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/3 16:08:44

Windows下用C++调用libcurl模拟iTunes账号登录的完整VS工程

本文还有配套的精品资源,点击获取 简介:一套开箱即用的Visual Studio C项目,专为在Windows平台实现iTunes账号登录流程而设计。项目基于libcurl库构建HTTP客户端,通过标准POST请求与iTunes服务端通信,完整覆盖请求构…

作者头像 李华
网站建设 2026/6/3 16:07:59

生命 不是 孤立系统。它是一个 开放系统。

它的本质是:**“孤立”意味着 断连 (Disconnected) 和 死寂 (Dead)。“开放”意味着 交互 (Interaction) 和 演化 (Evolution)。 孤立系统 (Isolated System):不与外界交换物质或能量。熵增不可逆,最终达到热平衡(最大无序&#x…

作者头像 李华
网站建设 2026/6/3 16:03:09

企业级项目管理系统Leantime的生产环境部署架构设计

企业级项目管理系统Leantime的生产环境部署架构设计 【免费下载链接】leantime Leantime is a goals focused project management system for non-project managers. Building with ADHD, Autism, and dyslexia in mind. 项目地址: https://gitcode.com/GitHub_Trending/le/l…

作者头像 李华
网站建设 2026/6/3 16:00:52

DXVK终极指南:在Linux/Wine上解决Direct3D应用HDR兼容性问题

DXVK终极指南:在Linux/Wine上解决Direct3D应用HDR兼容性问题 【免费下载链接】dxvk Vulkan-based implementation of D3D8, 9, 10 and 11 for Linux / Wine 项目地址: https://gitcode.com/gh_mirrors/dx/dxvk DXVK是一个基于Vulkan的Direct3D实现层&#xf…

作者头像 李华
网站建设 2026/6/3 15:53:58

构建高性能LCU工具:League Akari微内核架构深度解析

构建高性能LCU工具:League Akari微内核架构深度解析 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League Akari是一款基于英雄联…

作者头像 李华