Loading......

文章背景图

🔍 字节 面试 SQL

2025-12-25
19
-
- 分钟

一、SQL核心考点与高频题型 🗄️

📝 基础高频原题回顾

  • 连续登陆至少两天的用户

  • 最大连续登陆天数

  • 共同好友≥3 的用户对

🔍 补充字节高频SQL题

  • 统计每个用户近 7 天累计登陆时长(滑动窗口应用)

  • 计算用户留存率(次日 /7 日留存,业务核心指标)

  • 找出每个类别下金额 Top3 的订单(经典 TopN 问题)

  • 行列转换(用户多维度行为统计常用场景)

✍️ 详细解题解析(MySQL语法)

题1:连续登陆至少两天的用户

📋 表结构(user_login):

| user_id | login_date |
|---------|------------|
| 1       | 2025-01-01 |
| 1       | 2025-01-02 |
| 2       | 2025-01-01 |
| 3       | 2025-01-01 |
| 3       | 2025-01-02 |
| 3       | 2025-01-03 |

💡 解题思路:

  1. ROW_NUMBER()窗口函数按用户分组,对登陆日期升序排序;

  2. 计算login_date - 排序值,连续的登陆日期计算后结果会保持一致(核心逻辑);

  3. 按用户 + 上述计算差值分组,统计分组内记录数(即连续天数),筛选出连续天数≥2 的用户。

💻 SQL 实现:

WITH login_rn AS (
    SELECT 
        user_id,
        login_date,
        -- 关键:连续日期的差值固定,形成分组标识
        DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY login_date) DAY) AS diff
    FROM user_login
    GROUP BY user_id, login_date  -- 去重:同一用户同一天多次登陆算一次有效登陆
),
continuous_login AS (
    SELECT 
        user_id,
        COUNT(*) AS continuous_days
    FROM login_rn
    GROUP BY user_id, diff
    HAVING COUNT(*) >= 2  -- 筛选连续至少2天的记录
)
SELECT DISTINCT user_id  -- 去重得到目标用户
FROM continuous_login;

📌 考点:窗口函数(ROW_NUMBER)的应用、日期运算逻辑、连续值分组判断。

题2:最大连续登陆天数

💡 解题思路:

基于题 1 的中间结果(login_rn),新增一层分组,按用户聚合,取连续天数的最大值即可。

💻 SQL 实现:

WITH login_rn AS (
    SELECT 
        user_id,
        login_date,
        DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY login_date) DAY) AS diff
    FROM user_login
    GROUP BY user_id, login_date
),
continuous_stats AS (
    SELECT 
        user_id,
        diff,
        COUNT(*) AS continuous_days
    FROM login_rn
    GROUP BY user_id, diff
)
SELECT 
    user_id,
    MAX(continuous_days) AS max_continuous_days  -- 取每个用户的最大连续天数
FROM continuous_stats
GROUP BY user_id;

🌟 拓展:若需统计全平台用户的最大连续登陆天数,最后一层改为SELECT MAX(continuous_days) FROM continuous_stats;

题3:共同好友≥3的用户对

📋 表结构(friend_relation):

| user_id | friend_id |
|---------|-----------|
| 1       | 2         |
| 1       | 3         |
| 1       | 4         |
| 1       | 5         |
| 2       | 1         |
| 2       | 3         |
| 2       | 4         |
| 3       | 1         |
| 3       | 2         |

💡 解题思路:

  1. 自连接好友关系表,匹配两个用户共同的好友记录;

  2. 通过a.user_id < b.user_id限定条件,避免用户对重复(如 (1,2) 和(2,1)视为同一组);

  3. 按用户对分组,统计共同好友数量,筛选出数量≥3 的组合。

💻 SQL 实现:

WITH friend_pair AS (
    -- 自连接找共同好友,限定user1 < user2去重
    SELECT 
        a.user_id AS user1,
        b.user_id AS user2,
        a.friend_id AS common_friend
    FROM friend_relation a
    JOIN friend_relation b 
        ON a.friend_id = b.friend_id  -- 好友ID匹配,即共同好友
        AND a.user_id < b.user_id     -- 核心去重逻辑
)
SELECT 
    user1,
    user2,
    COUNT(common_friend) AS common_friend_count
FROM friend_pair
GROUP BY user1, user2
HAVING COUNT(common_friend) >= 3;

📌 考点:自连接的应用、分组去重逻辑、聚合统计。

题4:统计每个用户近7天累计登陆时长

📋 表结构(user_login_duration):

| user_id | login_time          | duration_min |
|---------|---------------------|--------------|
| 1       | 2025-01-01 08:00:00 | 30           |
| 1       | 2025-01-05 10:00:00 | 60           |
| 2       | 2025-01-06 14:00:00 | 45           |

💡 解题思路:

使用SUM() OVER()滑动窗口函数,按用户分组、登陆时间排序,窗口范围限定为“当前行及之前 7 天”,累计计算登陆时长。

💻 SQL 实现:

SELECT 
    user_id,
    login_time,
    SUM(duration_min) OVER(
        PARTITION BY user_id 
        ORDER BY login_time 
        RANGE BETWEEN INTERVAL 7 DAY PRECEDING AND CURRENT ROW  -- 近7天滑动窗口
    ) AS last7d_total_duration
FROM user_login_duration;

📌 考点:滑动窗口函数的范围限定(时间维度)、累计聚合统计。

题5:计算次日留存率

📖 定义:次日留存率 = 首日登陆且次日也登陆的用户数 / 首日登陆的总用户数(业务核心指标,衡量用户粘性)

📋 表结构:同题 1 的 user_login(以 2025-01-01 为首日统计)

💡 解题思路:

  1. 筛选首日(2025-01-01)登陆的用户集合;

  2. 筛选首日登陆且次日(2025-01-02)也登陆的用户集合;

  3. 用两个集合的用户数做除法,得到次日留存率。

💻 SQL 实现:

WITH first_login AS (
    -- 首日(2025-01-01)登陆的用户
    SELECT DISTINCT user_id 
    FROM user_login 
    WHERE login_date = '2025-01-01'
),
second_login AS (
    -- 首日登陆且次日也登陆的用户
    SELECT DISTINCT fl.user_id 
    FROM first_login fl
    JOIN user_login ul 
        ON fl.user_id = ul.user_id 
        AND ul.login_date = '2025-01-02'
)
SELECT 
    -- 左连接确保首日所有用户都被统计,避免分母为0
    COUNT(DISTINCT sl.user_id) / COUNT(DISTINCT fl.user_id) AS next_day_retention
FROM first_login fl
LEFT JOIN second_login sl ON fl.user_id = sl.user_id;

🌟 拓展:7 日留存率计算逻辑类似,只需将次日日期改为首日 +7 天(如 2025-01-08)。

题6:每个类别下金额Top3的订单

📋 表结构(order_info):

| order_id | category | amount |
|----------|----------|--------|
| 1        | A        | 100    |
| 2        | A        | 200    |
| 3        | A        | 150    |
| 4        | A        | 180    |
| 5        | B        | 300    |

💡 解题思路:

DENSE_RANK()(或ROW_NUMBER())窗口函数按类别分组、金额降序排序,筛选排名≤3 的订单(注意:DENSE_RANK 支持并列排名,ROW_NUMBER 会打破并列)。

💻 SQL 实现:

WITH order_rank AS (
    SELECT 
        *,
        -- DENSE_RANK():并列排名;ROW_NUMBER():唯一排名,根据需求选择
        DENSE_RANK() OVER(PARTITION BY category ORDER BY amount DESC) AS rk
    FROM order_info
)
SELECT * 
FROM order_rank 
WHERE rk <= 3;

📌 考点:窗口排序函数的应用、TopN 问题的通用解法。

✍️ SQL核心考点梳理

  1. 窗口函数:ROW_NUMBER/RANK/DENSE_RANK/SUM OVER 等的灵活应用;

  2. 连续值判断:日期运算 + 分组聚合的核心逻辑(面试高频场景);

  3. 多表关联:自连接、左连接的应用(如共同好友、留存率计算);

  4. 滑动窗口统计:时间维度的累计 / 均值统计(近 N 天、近 N 小时);

  5. 经典业务场景:TopN、行列转换、用户行为统计(留存、活跃、转化)。

🌟 SQL备考建议

重点练习业务场景题,理解“窗口函数 + 分组聚合”的核心逻辑,而非死记代码;每道题先梳理思路,再写代码,关注边界情况(如去重、分母为 0 等)。

评论交流