大厂SQL面试通关秘籍:腾讯/字节/阿里/美团/京东真题详解
- 2026-09-18 20:15:38
对于想进入互联网大厂的数据分析师来说,SQL是面试中必考的硬技能。本文精选了腾讯、字节跳动、阿里巴巴、美团、京东五家大厂的典型SQL面试题,每家公司2-3道,帮助你提前做好准备。
一、腾讯篇
题目1:连续登录天数统计
场景:用户登录表 user_login,包含字段 user_id(用户ID)、login_date(登录日期)。
要求:查询每个用户连续登录的最大天数。
示例数据:
参考答案:
WITH login_with_grp AS ( 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 user_login)SELECT user_id,grp, COUNT(*) AS continuous_daysFROM login_with_grpGROUP BY user_id, grpORDER BY continuous_days DESCLIMIT 1;考点解析:
• 使用 ROW_NUMBER()窗口函数生成序号• 用日期减去序号,连续日期的差值相同,形成分组标识 • 按用户和分组标识聚合,统计每组天数
题目2:分组TopN问题
场景:订单表 orders,包含 user_id、order_id、amount、order_time。
要求:查询每个用户金额最高的前3笔订单。
参考答案:
SELECT user_id, order_id, amount, order_timeFROM ( SELECT user_id, order_id, amount, order_time, ROW_NUMBER() OVER (PARTITION BY user_idORDER BY amount DESC ) AS rn FROM orders) tWHERE rn <= 3;考点解析:
• ROW_NUMBER()为每个分组内数据排序编号• 外层筛选 rn <= 3获取Top3• 注意区分 ROW_NUMBER()、RANK()、DENSE_RANK()的差异
题目3:用户留存率计算
场景:用户注册表 users(user_id, register_date)和用户活跃表 active(user_id, active_date)。
要求:计算每日新增用户的次日留存率、7日留存率。
参考答案:
WITH new_users AS ( SELECT register_date, COUNT(DISTINCT user_id) AS new_user_cnt FROM users GROUP BY register_date),retention AS ( SELECT u.register_date, COUNT(DISTINCT CASE WHEN DATEDIFF(a.active_date, u.register_date) = 1 THEN a.user_id END) AS d1_retained, COUNT(DISTINCT CASE WHEN DATEDIFF(a.active_date, u.register_date) = 7 THEN a.user_id END) AS d7_retained FROM users u LEFT JOIN active a ON u.user_id = a.user_id GROUP BY u.register_date)SELECT n.register_date, n.new_user_cnt, ROUND(r.d1_retained * 100.0 / n.new_user_cnt, 2) AS d1_retention_rate, ROUND(r.d7_retained * 100.0 / n.new_user_cnt, 2) AS d7_retention_rateFROM new_users nJOIN retention r ON n.register_date = r.register_date;考点解析:
• 留存率是数据分析核心指标 • 使用 DATEDIFF计算日期间隔• CASE WHEN条件计数实现留存统计
二、字节跳动篇
题目4:行列转换(行转列)
场景:学生成绩表 scores,包含 student_id、subject、score。
要求:将科目从行转为列,显示每个学生的各科成绩。
参考答案:
SELECT student_id, MAX(CASE WHEN subject = '数学' THEN score END) AS math_score, MAX(CASE WHEN subject = '语文' THEN score END) AS chinese_score, MAX(CASE WHEN subject = '英语' THEN score END) AS english_scoreFROM scoresGROUP BY student_id;考点解析:
• 使用 CASE WHEN+ 聚合函数实现行转列• 也可用 PIVOT(部分数据库支持)
题目5:中位数计算
场景:员工薪资表 salary(employee_id, salary)。
要求:计算薪资的中位数。
参考答案:
SELECT AVG(salary) AS median_salaryFROM ( SELECT salary, ROW_NUMBER() OVER (ORDER BY salary) AS rn_asc, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn_desc FROM salary) tWHERE rn_asc BETWEEN rn_desc - 1 AND rn_desc + 1;考点解析:
• 利用正序和倒序序号相等或相邻的特性定位中位数 • 奇数条记录取中间值,偶数条记录取中间两个的平均
题目6:漏斗分析
场景:用户行为表 user_actions,包含 user_id、action(步骤:view/click/order/pay)、action_time。
要求:计算从浏览到支付的各环节转化率。
参考答案:
WITH funnel AS ( SELECT user_id, MAX(CASE WHEN action = 'view' THEN 1 END) AS viewed, MAX(CASE WHEN action = 'click' THEN 1 END) AS clicked, MAX(CASE WHEN action = 'order' THEN 1 END) AS ordered, MAX(CASE WHEN action = 'pay' THEN 1 END) AS paid FROM user_actions GROUP BY user_id)SELECT SUM(viewed) AS view_cnt, SUM(clicked) AS click_cnt, SUM(ordered) AS order_cnt, SUM(paid) AS pay_cnt, ROUND(SUM(clicked) * 100.0 / SUM(viewed), 2) AS view_to_click, ROUND(SUM(ordered) * 100.0 / SUM(clicked), 2) AS click_to_order, ROUND(SUM(paid) * 100.0 / SUM(ordered), 2) AS order_to_pay, ROUND(SUM(paid) * 100.0 / SUM(viewed), 2) AS total_conversionFROM funnel;考点解析:
• 漏斗分析是互联网产品分析的核心场景 • 使用条件聚合统计各步骤用户数 • 计算相邻步骤及整体转化率
三、阿里巴巴篇
题目7:累计求和与移动平均
场景:每日销售额表 daily_sales(sale_date, amount)。
要求:计算每日销售额、累计销售额、近7日移动平均。
参考答案:
SELECT sale_date, amount, SUM(amount) OVER (ORDER BY sale_date) AS cumulative_amount, AVG(amount) OVER ( ORDER BY sale_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW ) AS moving_avg_7dFROM daily_sales;考点解析:
• SUM() OVER实现累计求和• ROWS BETWEEN定义窗口范围计算移动平均
题目8:环比/同比增长率
场景:月度销售表 monthly_sales(year_month, sales_amount)。
要求:计算每月销售额的环比增长率和同比增长率。
参考答案:
WITH sales_with_lag AS ( SELECT year_month, sales_amount, LAG(sales_amount, 1) OVER (ORDER BY year_month) AS last_month, LAG(sales_amount, 12) OVER (ORDER BY year_month) AS last_year FROM monthly_sales)SELECT year_month, sales_amount, ROUND((sales_amount - last_month) * 100.0 / last_month, 2) AS mom_growth, ROUND((sales_amount - last_year) * 100.0 / last_year, 2) AS yoy_growthFROM sales_with_lag;考点解析:
• LAG()函数获取前N行数据• 环比(MoM)对比上月,同比(YoY)对比去年同月
题目9:用户分层(RFM模型)
场景:用户消费表 user_transactions(user_id, order_date, amount)。
要求:根据最近消费时间(Recency)、消费频率(Frequency)、消费金额(Monetary)对用户分层。
参考答案:
WITH rfm AS ( SELECT user_id, DATEDIFF(CURRENT_DATE, MAX(order_date)) AS recency, COUNT(DISTINCT order_date) AS frequency, SUM(amount) AS monetary FROM user_transactions WHERE order_date >= DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR) GROUP BY user_id),rfm_score AS ( SELECT user_id, recency, frequency, monetary, NTILE(5) OVER (ORDER BY recency DESC) AS r_score, NTILE(5) OVER (ORDER BY frequency) AS f_score, NTILE(5) OVER (ORDER BY monetary) AS m_score FROM rfm)SELECT user_id, recency, frequency, monetary, r_score, f_score, m_score, CASE WHEN r_score >= 4 AND f_score >= 4 AND m_score >= 4 THEN '重要价值客户' WHEN r_score >= 4 AND f_score >= 4 THEN '重要保持客户' WHEN r_score >= 4 AND m_score >= 4 THEN '重要发展客户' WHEN f_score >= 4 AND m_score >= 4 THEN '重要挽留客户' ELSE '一般客户' END AS user_segmentFROM rfm_score;考点解析:
• RFM是经典的用户价值分层模型 • NTILE()将数据分为N等份,便于打分• 根据R、F、M得分组合定义用户标签
四、美团篇
题目10:时段订单分布
场景:订单表 orders(order_id, order_time, amount)。
要求:统计每小时的订单量和销售额分布。
参考答案:
SELECT HOUR(order_time) AS hour_of_day, COUNT(*) AS order_cnt, SUM(amount) AS total_amount, ROUND(AVG(amount), 2) AS avg_amountFROM ordersWHERE order_time >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)GROUP BY HOUR(order_time)ORDER BY hour_of_day;考点解析:
• HOUR()提取时间的小时部分• 时段分析常用于运营策略制定
题目11:商家销售额排名
场景:订单表 orders(merchant_id, order_id, amount)。
要求:查询销售额Top10的商家,并显示其排名。
参考答案:
WITH merchant_sales AS ( SELECT merchant_id, SUM(amount) AS total_sales, RANK() OVER (ORDER BY SUM(amount) DESC) AS sales_rank FROM orders GROUP BY merchant_id)SELECT merchant_id, total_sales, sales_rankFROM merchant_salesWHERE sales_rank <= 10;考点解析:
• 先聚合再排序,注意窗口函数在聚合后的使用 • RANK()处理并列排名
题目12:复购率计算
场景:订单表 orders(user_id, order_id, order_time)。
要求:计算每月的新客数和复购率。
参考答案:
WITH user_first_order AS ( SELECT user_id, DATE_FORMAT(MIN(order_time), '%Y-%m') AS first_month FROM orders GROUP BY user_id),monthly_stats AS ( SELECT DATE_FORMAT(o.order_time, '%Y-%m') AS month, COUNT(DISTINCT o.user_id) AS total_users, COUNT(DISTINCT CASE WHEN u.first_month = DATE_FORMAT(o.order_time, '%Y-%m') THEN o.user_id END) AS new_users FROM orders o JOIN user_first_order u ON o.user_id = u.user_id GROUP BY DATE_FORMAT(o.order_time, '%Y-%m'))SELECT month, total_users, new_users, total_users - new_users AS returning_users, ROUND((total_users - new_users) * 100.0 / total_users, 2) AS repurchase_rateFROM monthly_stats;考点解析:
• 先找出每个用户的首次购买月份 • 通过对比判断新客还是老客 • 复购率 = 老客数 / 总用户数
五、京东篇
题目13:库存周转天数
场景:商品库存表 inventory(sku_id, date, stock_qty)和销售表 sales(sku_id, date, sale_qty)。
要求:计算每个SKU近30天的平均库存周转天数。
参考答案:
WITH daily_data AS ( SELECT i.sku_id, i.date, i.stock_qty, COALESCE(s.sale_qty, 0) AS sale_qty FROM inventory i LEFT JOIN sales s ON i.sku_id = s.sku_id AND i.date = s.date WHERE i.date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)),sku_stats AS ( SELECT sku_id, AVG(stock_qty) AS avg_stock, SUM(sale_qty) AS total_sales FROM daily_data GROUP BY sku_id)SELECT sku_id, avg_stock, total_sales, CASE WHEN total_sales = 0 THEN NULL ELSE ROUND(avg_stock * 30 / total_sales, 2) END AS turnover_daysFROM sku_stats;考点解析:
• 库存周转天数 = 平均库存 / 日均销量 • 电商供应链分析的核心指标
题目14:异常订单检测
场景:订单表 orders(user_id, order_id, amount, order_time)。
要求:找出疑似刷单的用户(1小时内下单超过5次或单日消费超过平均3倍)。
参考答案:
WITH user_stats AS ( SELECT user_id, DATE(order_time) AS order_date, COUNT(*) AS order_cnt, SUM(amount) AS daily_amount, AVG(amount) AS avg_order_amount FROM orders GROUP BY user_id, DATE(order_time)),hourly_stats AS ( SELECT user_id, DATE_FORMAT(order_time, '%Y-%m-%d %H:00:00') AS hour_slot, COUNT(*) AS hourly_cnt FROM orders GROUP BY user_id, DATE_FORMAT(order_time, '%Y-%m-%d %H:00:00')),avg_stats AS ( SELECT AVG(daily_amount) AS overall_avg_amount FROM user_stats)SELECT DISTINCT u.user_id, '高频下单' AS risk_typeFROM hourly_stats hWHERE h.hourly_cnt > 5UNIONSELECT DISTINCT u.user_id, '异常高额' AS risk_typeFROM user_stats u left join avg_stats a on 1=1WHERE u.daily_amount > a.overall_avg_amount * 3;考点解析:
• 风控场景常用SQL分析 • 多维度异常检测(频率、金额) • 使用 UNION合并不同规则的异常用户
面试准备建议
1. 核心知识点
2. 常见考点总结
窗口函数必会:
• ROW_NUMBER()/RANK()/DENSE_RANK()—— 排名类问题• LAG()/LEAD()—— 同比环比、前后行对比• SUM() OVER/AVG() OVER—— 累计、移动计算
业务场景必会:
• 留存率计算(次日、7日、30日) • 漏斗分析(转化率) • RFM用户分层 • 复购率、活跃度统计
3. 面试技巧
1. 先理解业务场景:明确题目要求,不清楚的地方及时提问 2. 写出思路再写SQL:先用伪代码或文字描述逻辑 3. 考虑边界情况:空值处理、数据异常、性能优化 4. 熟悉你的简历:写上去的SQL项目要能讲清楚
结语
SQL是数据分析师的基本功,大厂面试中SQL考核通常占30%-50%的比重。建议大家在理解这些真题的基础上,多动手练习,形成自己的解题思路。
练习资源推荐:
• LeetCode Database 题目 • 牛客网 SQL 专项练习 • 自己搭建测试数据模拟业务场景
祝各位面试顺利,早日拿到心仪的大厂offer!
本文作者:鹏哥数个数专注数据分析与职场成长,欢迎关注交流! #互联网大厂 #面试题 #hivesql #sql面试题 #数据分析 #数据分析师 #窗口函数 #腾讯 #京东 #字节 #美团 #阿里巴巴 #SQL面试真题