一、数据分析师面试全景图
面试前最重要的是理解企业到底在考察什么。很多候选人刷了几百道SQL题,却在业务题面前哑口无言。让我先帮你理清面试的全局。
1.1 面试环节全览
笔试/在线测评:通常是SQL、Python编程或业务分析题,限时完成。这是第一道关卡,通过率通常在30-40%。
一面(技术面):深入考察SQL、Python/统计学基础。面试官会看你解决问题的思路,而不只是对错。
二面(业务面):基于业务场景的案例分析。给你一个业务问题,看你如何拆解、分析、给出建议。
三面(主管面):综合素质考察。沟通能力、团队协作、对行业的理解都可能涉及。
HR面/Offer沟通:薪酬福利、职业发展等问题的沟通。

1.2 各环节考察重点
| 环节 | 考察重点 | 淘汰率 |
|---|---|---|
| 笔试测评 | SQL、Python、统计学基础 | 60% |
| 技术一面 | SQL进阶、Python数据处理 | 40% |
| 业务二面 | 业务理解、指标拆解 | 30% |
| 主管三面 | 综合能力、职业规划 | 20% |
| HR面 | 薪资谈判、稳定性 | 10% |
1.3 不同公司的偏好
大厂(阿里、腾讯、字节等):重视基础扎实程度,会深入追问原理。算法能力也要具备,SQL题难度较高。
中厂(独角兽、新锐公司):重视实战能力,会有较多的业务场景题。强调能快速上手产出价值。
外企:重视沟通表达,英文能力。技术题相对简单,但对业务理解要求更高。
传统企业/金融:重视统计学基础和严谨性。SQL题相对简单,但会有数据治理方面的考察。
二、SQL面试题库与详解
SQL是数据分析师的立身之本,也是面试中最能拉开差距的环节。
2.1 基础查询类
题目1:查找重复邮箱
plaintext
用户表users包含字段:id, email, name, created_at
请找出所有重复的邮箱地址
解题思路:
- 使用GROUP BY按邮箱分组
- 用HAVING筛选出现次数大于1的
- 关键点:GROUP BY + HAVING组合
sql
SELECT email, COUNT(*) as cnt
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
延伸追问:如何删除重复的邮箱,保留ID最小的那条?
sql
-- 保留ID最小的,删除其他的
DELETE FROM users
WHERE id NOT IN (
SELECT MIN(id)
FROM users
GROUP BY email
);
2.2 窗口函数类(高频!)
题目2:连续登录天数
plaintext
用户登录表user_login:user_id, login_date
找出每个用户连续登录的最长天数
解题思路:
- 给登录日期排名
- 用日期减去排名,得到相同的差值意味着连续
- 按用户和差值分组,统计天数
sql
WITH ranked AS (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) as rn
FROM user_login
GROUP BY user_id, login_date
),
grouped AS (
SELECT
user_id,
DATE_SUB(login_date, INTERVAL rn DAY) as grp,
COUNT(*) as consecutive_days
FROM ranked
GROUP BY user_id, DATE_SUB(login_date, INTERVAL rn DAY)
)
SELECT
user_id,
MAX(consecutive_days) as max_consecutive_days
FROM grouped
GROUP BY user_id;
题目3:用户留存率计算
plaintext
用户注册表users:user_id, register_date
用户行为表actions:user_id, action_date, action_type
计算2026-01-01新增用户的次日留存率、7日留存率
sql
WITH new_users AS (
SELECT user_id
FROM users
WHERE register_date = '2026-01-01'
),
retention AS (
SELECT
DATEDIFF(action_date, register_date) as days_diff,
COUNT(DISTINCT a.user_id) as users
FROM actions a
JOIN new_users n ON a.user_id = n.user_id
WHERE action_type = 'login'
GROUP BY DATEDIFF(action_date, register_date)
)
SELECT
(SELECT COUNT(DISTINCT user_id) FROM new_users) as total_users,
MAX(CASE WHEN days_diff = 1 THEN users END) as day1_users,
MAX(CASE WHEN days_diff = 7 THEN users END) as day7_users,
ROUND(MAX(CASE WHEN days_diff = 1 THEN users END) * 100.0 /
(SELECT COUNT(*) FROM new_users), 2) as day1_rate,
ROUND(MAX(CASE WHEN days_diff = 7 THEN users END) * 100.0 /
(SELECT COUNT(*) FROM new_users), 2) as day7_rate
FROM retention;
2.3 业务分析类
题目4:用户分群
plaintext
订单表orders:order_id, user_id, order_amount, order_date, status
找出高价值用户(最近30天有消费且累计消费金额>1000)
sql
WITH recent_orders AS (
SELECT
user_id,
SUM(order_amount) as total_amount,
COUNT(order_id) as order_count,
MAX(order_date) as last_order_date
FROM orders
WHERE order_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
AND status = 'completed'
GROUP BY user_id
)
SELECT *
FROM recent_orders
WHERE total_amount > 1000
ORDER BY total_amount DESC;
面试追问:如何给这些高价值用户打标签?用什么SQL实现RFM分群?
sql
-- RFM模型:最近(Recency)、频率(Frequency)、金额(Monetary)
WITH rfm AS (
SELECT
user_id,
DATEDIFF(CURDATE(), MAX(order_date)) as recency, -- 越近越好
COUNT(order_id) as frequency, -- 越多越好
SUM(order_amount) as monetary -- 越高越好
FROM orders
WHERE status = 'completed'
GROUP BY user_id
),
rfm_score AS (
SELECT
*,
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,
CONCAT(r_score, f_score, m_score) as rfm_code,
CASE
WHEN r_score = 5 AND f_score = 5 AND m_score = 5 THEN '高价值用户'
WHEN r_score >= 3 THEN '潜力用户'
WHEN f_score >= 3 THEN '忠诚用户'
WHEN r_score <= 2 AND f_score <= 2 THEN '流失风险用户'
ELSE '普通用户'
END as user_segment
FROM rfm_score;
三、Python数据分析面试题
3.1 pandas数据处理
题目5:数据合并与清洗
python
import pandas as pd
# 给定两个DataFrame,users和orders,合并后找出没有订单的用户
users = pd.DataFrame({
'user_id': [1, 2, 3, 4],
'name': ['张三', '李四', '王五', '赵六']
})
orders = pd.DataFrame({
'user_id': [1, 1, 2, 3],
'order_amount': [100, 200, 150, 300]
})
# 方法1:merge + 筛选
merged = users.merge(orders, on='user_id', how='left')
no_order_users = merged[merged['order_amount'].isna()]
print(no_order_users)
# 方法2:isin
users[~users['user_id'].isin(orders['user_id'])]
题目6:分组统计与聚合
python
# 找出每个部门的工资排名前两位的员工
employees = pd.DataFrame({
'dept': ['技术', '技术', '技术', '产品', '产品'],
'name': ['张三', '李四', '王五', '赵六', '孙七'],
'salary': [15000, 18000, 12000, 16000, 14000]
})
# 使用groupby + nlargest
result = (employees.groupby('dept')
.apply(lambda x: x.nlargest(2, 'salary'))
.reset_index(drop=True))
print(result)
3.2 数据可视化
题目7:用matplotlib/seaborn绘制留存曲线
python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 计算留存率曲线
def calculate_retention_curve(df, cohort_date):
"""计算留存曲线"""
result = []
for days in range(0, 31):
target_date = cohort_date + pd.Timedelta(days=days)
if days == 0:
users = df[df['register_date'] == cohort_date]['user_id'].unique()
count = len(users)
else:
count = df[(df['action_date'] == target_date) &
(df['user_id'].isin(users))]['user_id'].nunique()
result.append({'day': days, 'retention': count / len(users) * 100})
return pd.DataFrame(result)
# 绘制留存曲线
plt.figure(figsize=(10, 6))
sns.lineplot(data=retention_df, x='day', y='retention', marker='o')
plt.title('用户留存曲线', fontsize=14)
plt.xlabel('天数', fontsize=12)
plt.ylabel('留存率(%)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.show()
3.3 统计问题
题目8:AB测试相关
python
from scipy import stats
# 假设对照组转化率0.12,实验组转化率0.15,样本量各10000
control_conversions = 0.12 * 10000
experiment_conversions = 0.15 * 10000
n_control = n_experiment = 10000
# Z检验
p_control = control_conversions / n_control
p_experiment = experiment_conversions / n_experiment
pooled_p = (control_conversions + experiment_conversions) / (n_control + n_experiment)
se = (pooled_p * (1 - pooled_p) * (1/n_control + 1/n_experiment)) ** 0.5
z_stat = (p_experiment - p_control) / se
p_value = 2 * (1 - stats.norm.cdf(abs(z_stat)))
print(f"Z统计量: {z_stat:.4f}")
print(f"P值: {p_value:.4f}")
if p_value < 0.05:
print("差异显著,实验方案更好")
else:
print("差异不显著,不能判断实验方案更好")
四、业务场景分析题
4.1 指标拆解类
题目9:DAU下降如何分析?
这是一个经典的业务分析题,考察的是你分析问题的框架和逻辑。
回答框架:
- 确认数据准确性
- 检查数据埋点是否正常
- 核对数据更新时间
- 确认口径是否一致
- 维度拆分
- 时间维度:工作日/周末、节假日对比
- 用户维度:新用户/老用户、渠道来源
- 产品维度:端(App/小程序/H5)、版本
- 地域维度:各地区DAU对比
- 假设验证
- 假设1:某个渠道流量下降?
验证:拆分各渠道UV,看是否有异常 - 假设2:产品改版导致?
验证:对比改版前后数据 - 假设3:竞品影响?
验证:行业数据、竞品动态
- 假设1:某个渠道流量下降?
- 给出结论和建议
- 明确主要原因
- 提出可落地的建议
- 后续监控计划
4.2 实验设计类
题目10:如何设计一个推荐策略的AB测试?
回答要点:
- 实验分组
- 分桶方式:user_id hash % 100
- 分桶比例:实验组20%,对照组80%(或各50%)
- AA验证:确保实验前两组指标无显著差异
- 核心指标选择
- 主指标:点击率、转化率、GMV
- 护栏指标:延迟、崩溃率(不能变差)
- 样本量计算
- 公式:n = 2 * (Z_α + Z_β)² * p(1-p) / δ²
- 预估MDE(最小可检测差异)
- 计算需要的样本量
- 实验周期
- 一般7-14天
- 覆盖一个完整周期(工作日+周末)
- 统计检验
- Z检验或T检验
- 多重检验校正(如Bonferroni)
五、面试技巧与注意事项
5.1 SQL答题技巧
读题三遍法:
- 第一遍:理解业务背景
- 第二遍:确定需要的表和字段
- 第三遍:思考解题思路再开始写
边写边说:面试官想看的不只是代码,还有你的思路。说出你的想法,即使卡住了也能展示思考过程。
先粗糙后优化:先写出能跑的代码,再考虑性能优化。很多时候简单解法就够了。
5.2 业务题答题技巧
STAR法则:Situation(背景)→ Task(任务)→ Action(行动)→ Result(结果)
用具体案例说明你的分析能力,而不是泛泛而谈”我会用数据分析问题”。
5.3 常见扣分项
| 扣分项 | 后果 | 建议 |
|---|---|---|
| SQL写错且不检查 | 直接扣分 | 写完后快速检查逻辑 |
| 问业务场景时只背理论 | 无法落地 | 多做模拟题,理解业务 |
| 遇到不会的题直接放弃 | 零分 | 说出思路,尝试解决 |
| 过度紧张影响发挥 | 表现打折 | 提前准备,模拟面试 |
结语
数据分析师的面试考察的是综合素质:技术基础是门槛,业务理解是加分项,沟通表达是催化剂。刷题是必要的,但不要盲目刷,把每道题理解透彻,形成自己的知识体系。机会总是留给有准备的人!

发表回复