跳到主要内容

携程大数据面试SQL-酒店+机票打包购买转化率

⚠️ 待修正

一、题目背景

这道题来自携程的数据分析岗面试。携程是在线旅游平台,数据分析师需要从海量业务数据中挖掘洞见。

业务场景:用户消费行为相关需求在日常工作中频繁出现,这类型的SQL题是面试高频考点。

一、题目

携程经常推出"机+酒"打包套餐产品,需要分析浏览了打包套餐页面的用户中有多少最终完成了购买。给定三张表:user_visit(用户浏览日志)、package_order(打包套餐订单)、hotel_order(单独酒店订单)和 flight_order(单独机票订单)。

user_visit 用户浏览日志表:

visit_iduser_idpage_typevisit_time
V001U201package2025-03-01 10:00:00
V002U202package2025-03-02 14:30:00
V003U203package2025-03-03 09:15:00
V004U204package2025-03-03 11:20:00
V005U201hotel2025-03-04 16:00:00
V006U205package2025-03-04 10:00:00
V007U202package2025-03-05 08:45:00
V008U203flight2025-03-05 12:30:00
V009U206package2025-03-06 09:00:00
V010U201package2025-03-06 15:20:00

package_order 打包套餐订单表:

order_iduser_idpackage_nameorder_timeamount
PKG001U201三亚5天4晚机+酒2025-03-02 20:00:005200
PKG002U202丽江3天2晚机+酒2025-03-06 10:00:003800
PKG003U204成都4天3晚机+酒2025-03-10 18:30:004100

分散购买记录(用户单独购买机票和酒店,而非打包):

order_iduser_idorder_typeorder_timeamount
FLT001U203flight2025-03-06 10:00:001800
HTL001U203hotel2025-03-06 10:05:002200
FLT002U205flight2025-03-10 14:00:001500
FLT003U206flight2025-03-12 09:00:002000

要求:

  1. 统计浏览过打包套餐页面的总独立用户数
  2. 统计这些用户中最终购买打包套餐的用户数
  3. 计算打包购买的转化率(购买打包套餐的用户数 / 浏览打包套餐的用户数)
  4. 分析:浏览了打包套餐但未购买打包套餐的用户,他们是否有单独购买机票或酒店?

三、思路分析

本题考察多表关联分析能力,核心是转化漏斗的计算。涉及 COUNT DISTINCT、多表 LEFT JOIN、以及转化率的分母定义。难点在于理清"浏览打包页-购买打包套餐-分散购买"三者之间的关系。

维度评分
题目难度⭐⭐⭐
题目清晰度⭐⭐⭐⭐
业务常见度⭐⭐⭐⭐⭐

解题思路:

  1. 先从 user_visit 中取出浏览过 page_type = 'package' 的独立用户集合
  2. LEFT JOIN 关联 package_order,标记用户是否购买打包套餐
  3. LEFT JOIN 关联分散购买记录(需要 UNION 机票和酒店订单),标记未购买打包套餐的用户是否有分散购买行为
  4. 计算各层级的用户数和转化率
  5. 注意:一个用户可能多次浏览,需要去重;分散购买表需要先 UNION 再关联

四、逐步推导

步骤1:统计浏览和购买打包套餐的用户数及转化率

WITH visited_users AS (
SELECT DISTINCT user_id
FROM user_visit
WHERE page_type = 'package'
),
package_buyers AS (
SELECT DISTINCT user_id
FROM package_order
)
SELECT
COUNT(DISTINCT v.user_id) AS visited_users,
COUNT(DISTINCT p.user_id) AS package_buyers,
CONCAT(
ROUND(
COUNT(DISTINCT p.user_id) * 100.0 / COUNT(DISTINCT v.user_id), 2
), '%'
) AS conversion_rate
FROM visited_users v
LEFT JOIN package_buyers p ON v.user_id = p.user_id;

执行结果:

visited_userspackage_buyersconversion_rate
6350.00%

步骤2:分析未购买打包套餐的用户是否有分散购买行为

WITH visited_users AS (
SELECT DISTINCT user_id
FROM user_visit
WHERE page_type = 'package'
),
package_buyers AS (
SELECT DISTINCT user_id
FROM package_order
),
separate_orders AS (
SELECT DISTINCT user_id, 'flight' AS buy_type FROM hotel_order
UNION
SELECT DISTINCT user_id, 'hotel' AS buy_type FROM flight_order
)
SELECT
v.user_id,
CASE WHEN p.user_id IS NOT NULL THEN '已购买打包套餐'
WHEN s.user_id IS NOT NULL THEN '未购打包,但有分散购买'
ELSE '未购打包,无任何购买'
END AS user_behavior
FROM visited_users v
LEFT JOIN package_buyers p ON v.user_id = p.user_id
LEFT JOIN separate_orders s ON v.user_id = s.user_id
ORDER BY v.user_id;

执行结果:

user_iduser_behavior
U201已购买打包套餐
U202已购买打包套餐
U203未购打包,但有分散购买
U204已购买打包套餐
U205未购打包,但有分散购买
U206未购打包,但有分散购买

五、常见坑点

坑1:各步骤COUNT DISTINCT口径需一致 — 如果时间窗口不同,转化率可能 >100%,出现诡异数据。

坑2:LEFT JOIN链过长导致性能爆炸 — 3-4层嵌套在大数据量下严重膨胀,可用 UNION ALL + CASE WHEN 替代。

六、举一反三

  1. 按骑手/站点/城市维度下钻:定位问题来源,是某个骑手还是某个区域的延迟率偏高

  2. 按延迟程度分级:CASE WHEN 分为轻微/中等/严重三级,关注严重延迟的占比

  3. 时段分析:按小时统计,识别午晚高峰时段的配送压力变化

七、知识点总结

考点说明
CASE WHEN 条件聚合灵活实现分段统计、条件计数、标签化处理
多表JOINLEFT JOIN保留主表所有数据,COALESCE处理NULL
COUNT DISTINCT 去重统计唯一用户/事件数,避免重复记录干扰聚合结果
日期函数DATEDIFF / DATE_ADD / unix_timestamp处理日期运算

八、建表语句和数据插入

点击展开 DDL & DML
-- 用户浏览日志表
CREATE TABLE user_visit (
visit_id VARCHAR(10) PRIMARY KEY,
user_id VARCHAR(10),
page_type VARCHAR(20),
visit_time DATETIME
);

INSERT INTO user_visit VALUES
('V001', 'U201', 'package', '2025-03-01 10:00:00'),
('V002', 'U202', 'package', '2025-03-02 14:30:00'),
('V003', 'U203', 'package', '2025-03-03 09:15:00'),
('V004', 'U204', 'package', '2025-03-03 11:20:00'),
('V005', 'U201', 'hotel', '2025-03-04 16:00:00'),
('V006', 'U205', 'package', '2025-03-04 10:00:00'),
('V007', 'U202', 'package', '2025-03-05 08:45:00'),
('V008', 'U203', 'flight', '2025-03-05 12:30:00'),
('V009', 'U206', 'package', '2025-03-06 09:00:00'),
('V010', 'U201', 'package', '2025-03-06 15:20:00');

-- 打包套餐订单表
CREATE TABLE package_order (
order_id VARCHAR(10) PRIMARY KEY,
user_id VARCHAR(10),
package_name VARCHAR(50),
order_time DATETIME,
amount DECIMAL(10,2)
);

INSERT INTO package_order VALUES
('PKG001', 'U201', '三亚5天4晚机+酒', '2025-03-02 20:00:00', 5200),
('PKG002', 'U202', '丽江3天2晚机+酒', '2025-03-06 10:00:00', 3800),
('PKG003', 'U204', '成都4天3晚机+酒', '2025-03-10 18:30:00', 4100);

-- 机票订单表
CREATE TABLE flight_order (
order_id VARCHAR(10) PRIMARY KEY,
user_id VARCHAR(10),
order_type VARCHAR(20),
order_time DATETIME,
amount DECIMAL(10,2)
);

INSERT INTO flight_order VALUES
('FLT001', 'U203', 'flight', '2025-03-06 10:00:00', 1800),
('FLT002', 'U205', 'flight', '2025-03-10 14:00:00', 1500),
('FLT003', 'U206', 'flight', '2025-03-12 09:00:00', 2000);

-- 酒店订单表
CREATE TABLE hotel_order (
order_id VARCHAR(10) PRIMARY KEY,
user_id VARCHAR(10),
order_type VARCHAR(20),
order_time DATETIME,
amount DECIMAL(10,2)
);

INSERT INTO hotel_order VALUES
('HTL001', 'U203', 'hotel', '2025-03-06 10:05:00', 2200);
📱关注公众号

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

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

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

交流微信二维码

你可能还想看