跳到主要内容

拼多多大数据面试SQL-新用户首单品类偏好分析

⚠️ 待修正

一、题目背景

这道题来自拼多多的数据分析岗面试。拼多多是社交裂变电商,数据分析师需要从海量业务数据中挖掘洞见。

业务场景:数据分析相关需求在日常工作中频繁出现,这类型的SQL题是面试高频考点。

一、题目

分析新用户(注册后7天内首次下单)的首单品类偏好分布,统计每个品类作为首单品类的新用户数及占比。

假设有两张表:

  • user_register:用户注册表
  • order_info:用户订单表
-- user_register 用户注册表
+---------+-------------------+
| user_id | register_time |
+---------+-------------------+
| u01 | 2025-06-01 08:00 |
| u02 | 2025-06-03 10:00 |
| u03 | 2025-06-05 11:00 |
| u04 | 2025-06-08 09:00 |
+---------+-------------------+

-- order_info 订单表
+----------+---------+----------+-------------------+
| order_id | user_id | category | order_time |
+----------+---------+----------+-------------------+
| 1001 | u01 | 食品 | 2025-06-02 10:00 |
| 1002 | u01 | 服装 | 2025-06-05 14:00 |
| 1003 | u02 | 数码 | 2025-06-04 09:00 |
| 1004 | u02 | 食品 | 2025-06-10 16:00 |
| 1005 | u03 | 服装 | 2025-06-08 12:00 |
| 1006 | u04 | 食品 | 2025-06-12 10:00 |
| 1007 | u04 | 数码 | 2025-06-15 08:00 |
| 1008 | u03 | 食品 | 2025-06-12 15:00 |
+----------+---------+----------+-------------------+

三、思路分析

  1. JOIN 用户注册表和订单表,筛选注册后7天内的订单(datediff(order_time, register_time) <= 7);
  2. 使用 ROW_NUMBER 按用户分组、按下单时间排序,标记每个用户的首单(序号=1);
  3. 筛选首单记录,按品类分组统计用户数及占比。
维度评分
题目难度⭐️⭐️⭐️
题目清晰度⭐️⭐️⭐️⭐️
业务常见度⭐️⭐️⭐️⭐️

四、逐步推导

1.筛选新用户首单记录

执行SQL

select user_id,
category,
order_time,
row_number() over (partition by user_id order by order_time) as rn
from (
select o.user_id,
o.category,
o.order_time
from user_register r
join order_info o
on r.user_id = o.user_id
where datediff(o.order_time, r.register_time) <= 7
) t

查询结果

+---------+----------+-------------------+-----+
| user_id | category | order_time | rn |
+---------+----------+-------------------+-----+
| u01 | 食品 | 2025-06-02 10:00 | 1 |
| u01 | 服装 | 2025-06-05 14:00 | 2 |
| u02 | 数码 | 2025-06-04 09:00 | 1 |
| u03 | 服装 | 2025-06-08 12:00 | 1 |
| u04 | 食品 | 2025-06-12 10:00 | 1 |
+---------+----------+-------------------+-----+

2.按品类统计新用户数及占比

执行SQL

select category,
count(distinct user_id) as new_user_cnt,
round(count(distinct user_id) / sum(count(distinct user_id)) over(), 4) as ratio
from (
select user_id,
category,
order_time,
row_number() over (partition by user_id order by order_time) as rn
from (
select o.user_id,
o.category,
o.order_time
from user_register r
join order_info o
on r.user_id = o.user_id
where datediff(o.order_time, r.register_time) <= 7
) t
) tt
where rn = 1
group by category

查询结果

+----------+--------------+--------+
| category | new_user_cnt | ratio |
+----------+--------------+--------+
| 食品 | 2 | 0.5000 |
| 数码 | 1 | 0.2500 |
| 服装 | 1 | 0.2500 |
+----------+--------------+--------+

五、常见坑点

坑1:NULL值的隐式处理 — 聚合函数跳过NULL,窗口函数不跳过。WHERE需显式过滤或用COALESCE替代。

坑2:数据类型不一致导致JOIN失效 — string vs int隐式转换可能触发全表扫描,性能骤降。

六、举一反三

  1. 增加时间维度对比:按天/周/月分组,观察指标的趋势和季节性波动

  2. 增加分组维度:按品类/地区/渠道拆解,发现差异化的业务洞察

  3. 设置预警阈值:在WHERE中加阈值判断,自动筛选异常数据

七、知识点总结

考点说明
ROW_NUMBER + 差值法连续问题经典解法:日期-行号=分组标识,相同差值同一连续段
多表JOINLEFT JOIN保留主表所有数据,COALESCE处理NULL
GROUP BY + 聚合函数分组聚合是数据分析的基础,配合HAVING筛选分组结果
日期函数DATEDIFF / DATE_ADD / unix_timestamp处理日期运算

八、建表语句和数据插入

点击展开 DDL & DML
--建表语句
CREATE TABLE user_register (
user_id string COMMENT '用户ID',
register_time string COMMENT '注册时间'
) COMMENT '用户注册表';

CREATE TABLE order_info (
order_id bigint COMMENT '订单ID',
user_id string COMMENT '用户ID',
category string COMMENT '商品品类',
order_time string COMMENT '下单时间'
) COMMENT '用户订单表';

-- 插入数据
insert into user_register(user_id, register_time) values
('u01', '2025-06-01 08:00'),
('u02', '2025-06-03 10:00'),
('u03', '2025-06-05 11:00'),
('u04', '2025-06-08 09:00');

insert into order_info(order_id, user_id, category, order_time) values
(1001, 'u01', '食品', '2025-06-02 10:00'),
(1002, 'u01', '服装', '2025-06-05 14:00'),
(1003, 'u02', '数码', '2025-06-04 09:00'),
(1004, 'u02', '食品', '2025-06-10 16:00'),
(1005, 'u03', '服装', '2025-06-08 12:00'),
(1006, 'u04', '食品', '2025-06-12 10:00'),
(1007, 'u04', '数码', '2025-06-15 08:00'),
(1008, 'u03', '食品', '2025-06-12 15:00');
📱关注公众号

「数据仓库技术」文章同步更新,不错过每一篇干货

微信公众号二维码
💬加群交流

备注「数据仓库技术」加入社群,每日一道大厂SQL真题

交流微信二维码

你可能还想看