使用 SQL 构建转化漏斗

每个企业都有一个"漏斗"------用户从首次访问网站到成为付费客户的路径。但大多数用户会在途中流失。

漏斗分析 帮助你精确定位他们在哪里流失。

  • 50% 的用户在着陆页后离开?
  • 80% 的用户放弃购物车?

在本指南中,我们将使用 SQL 从头开始构建一个转化漏斗。

转化漏斗阶段及流失百分比

数据模型

我们将使用一个简单的 events_funnel 表来跟踪用户操作:

示例数据(events_funnel 表)

user_id event_name event_time
1 view_landing 10:00
1 add_to_cart 10:05
1 purchase 10:10
2 view_landing 11:00
2 add_to_cart 11:05
3 view_landing 12:00

数据说明

  • user_id:用户唯一标识符
  • event_name:事件名称(view_landing、add_to_cart、purchase)
  • event_time:事件发生时间

这个简单的事件表可以跟踪用户在转化漏斗中的每个步骤。

方法 1:逐步聚合

构建漏斗最简单的方法是计算执行每个操作的唯一用户数。

查询示例

sql 复制代码
-- 简单的漏斗聚合
SELECT 
  event_name,
  COUNT(DISTINCT user_id) as users,
  -- 计算占总数的百分比(简化版)
  ROUND(100.0 * COUNT(DISTINCT user_id) / 
    (SELECT COUNT(DISTINCT user_id) FROM events_funnel), 2) as pct
FROM events_funnel
GROUP BY event_name
ORDER BY 
  CASE event_name
    WHEN 'view_landing' THEN 1
    WHEN 'add_to_cart' THEN 2
    WHEN 'purchase' THEN 3
  END;

查询结果

event_name users pct
view_landing 3 100.00
add_to_cart 2 66.67
purchase 1 33.33

结果解读

  • 着陆页:3 个用户访问(100%)
  • 加购物车:2 个用户添加商品(66.67%)
  • 购买:1 个用户完成购买(33.33%)

这种方法的问题

这种方法不保证顺序 。如果一个用户先执行了 purchase,然后才执行 view_landing,他们仍然会被计入两个步骤,即使他们没有遵循漏斗路径。

为什么会出现这个问题?

因为我们只是简单地计算每个事件的唯一用户数,而没有检查事件的顺序。在实际业务中,这可能导致:

  • 虚高的转化率:包含了不符合漏斗顺序的用户
  • 错误的优化方向:无法准确识别流失点
  • 误导性的洞察:数据不反映真实的用户旅程

方法 2:有序漏斗(使用左连接)

为了确保用户遵循步骤 1 -> 步骤 2 -> 步骤 3 的顺序,我们将步骤连接在一起。

示例数据(events_funnel_ordered 表)

user_id event_name event_time
1 view_landing 10:00
1 add_to_cart 10:05
1 purchase 10:10
2 view_landing 11:00
2 add_to_cart 11:05
3 view_landing 12:00
4 purchase 13:00
4 view_landing 13:05

查询示例

sql 复制代码
WITH landing_users AS (
  SELECT DISTINCT user_id 
  FROM events_funnel_ordered 
  WHERE event_name = 'view_landing'
),
cart_users AS (
  SELECT DISTINCT user_id 
  FROM events_funnel_ordered 
  WHERE event_name = 'add_to_cart'
),
purchase_users AS (
  SELECT DISTINCT user_id 
  FROM events_funnel_ordered 
  WHERE event_name = 'purchase'
)
SELECT 
  COUNT(DISTINCT l.user_id) as landing_users,
  COUNT(DISTINCT c.user_id) as cart_users,
  COUNT(DISTINCT p.user_id) as purchase_users,
  ROUND(100.0 * COUNT(DISTINCT c.user_id) / COUNT(DISTINCT l.user_id), 2) as landing_to_cart_pct,
  ROUND(100.0 * COUNT(DISTINCT p.user_id) / COUNT(DISTINCT c.user_id), 2) as cart_to_purchase_pct
FROM landing_users l
LEFT JOIN cart_users c ON l.user_id = c.user_id
LEFT JOIN purchase_users p ON c.user_id = p.user_id;

查询结果

landing_users cart_users purchase_users landing_to_cart_pct cart_to_purchase_pct
4 2 1 50.00 50.00

结果解读

  • 着陆页用户:4 个用户访问着陆页
  • 购物车用户:2 个用户添加商品到购物车(从着陆页的转化率为 50%)
  • 购买用户:1 个用户完成购买(从购物车的转化率为 50%)

为什么这种方法更好?

使用左连接确保了:

  • 顺序保证:只有先访问着陆页的用户才会被计入购物车步骤
  • 准确的转化率:反映真实的用户旅程
  • 可靠的洞察:帮助识别真正的流失点

查询解析

  1. landing_users CTE:提取所有访问着陆页的用户
  2. cart_users CTE:提取所有添加商品到购物车的用户
  3. purchase_users CTE:提取所有完成购买的用户
  4. LEFT JOIN:将步骤连接在一起,确保顺序
  5. 百分比计算:计算每个步骤之间的转化率

注意事项

  • 用户 4 先购买再访问着陆页,不会被计入有序漏斗
  • 这种方法更准确,但查询稍微复杂一些
  • 适用于需要严格顺序保证的场景

方法 3:单查询透视

对于高级用户,你可以使用 CASE WHEN 聚合在一次查询中完成。这在大数据集上速度更快。

查询示例

sql 复制代码
SELECT 
  COUNT(DISTINCT user_id) as total_users,
  COUNT(DISTINCT CASE WHEN event_name = 'add_to_cart' THEN user_id END) as cart_users,
  COUNT(DISTINCT CASE WHEN event_name = 'purchase' THEN user_id END) as purchase_users
FROM events_funnel;

查询结果

total_users cart_users purchase_users
3 2 1

为什么使用这种方法?

性能优势

  • 单次扫描:只需扫描表一次,而不是多次
  • 更快的执行:在大数据集上速度显著提升
  • 更少的内存:不需要创建多个 CTE

适用场景

  • 数据量大(百万级以上)
  • 需要快速响应
  • 不需要复杂的顺序检查

局限性

  • 不保证顺序(与方法 1 相同)
  • 不适合需要严格顺序保证的场景
  • 可读性稍差

性能对比

方法 表扫描次数 适用数据量 顺序保证
方法 1:逐步聚合 1 次 小到中等
方法 2:左连接 3 次 小到中等
方法 3:单查询透视 1 次

计算流失率

最重要的洞察是步骤之间的转化率

示例分析

如果你有:

  • 着陆页:1000 用户
  • 购物车:200 用户(20% 转化率)
  • 购买:50 用户(25% 转化率)

关键洞察

你知道最大的问题是让用户将商品添加到购物车,而不是结账!

为什么这很重要?

  • 优化方向:应该优先优化着陆页到购物车的转化,而不是购物车到购买的转化
  • 投资回报:提升 20% 的转化率比提升 25% 的转化率影响更大(基数更大)
  • 资源分配:将资源集中在最大的流失点

流失率计算公式

指标 公式 示例
转化率 (下一步用户数 / 当前步用户数) × 100% (200 / 1000) × 100% = 20%
流失率 100% - 转化率 100% - 20% = 80%
累计转化率 (最终步用户数 / 第一步用户数) × 100% (50 / 1000) × 100% = 5%

完整的漏斗分析查询

sql 复制代码
WITH funnel_steps AS (
  SELECT 
    COUNT(DISTINCT CASE WHEN event_name = 'view_landing' THEN user_id END) as step1_users,
    COUNT(DISTINCT CASE WHEN event_name = 'add_to_cart' THEN user_id END) as step2_users,
    COUNT(DISTINCT CASE WHEN event_name = 'purchase' THEN user_id END) as step3_users
  FROM events_funnel
)
SELECT 
  step1_users as landing_users,
  step2_users as cart_users,
  step3_users as purchase_users,
  ROUND(100.0 * step2_users / step1_users, 2) as landing_to_cart_conversion,
  ROUND(100.0 * (step1_users - step2_users) / step1_users, 2) as landing_to_cart_dropoff,
  ROUND(100.0 * step3_users / step2_users, 2) as cart_to_purchase_conversion,
  ROUND(100.0 * (step2_users - step3_users) / step2_users, 2) as cart_to_purchase_dropoff,
  ROUND(100.0 * step3_users / step1_users, 2) as overall_conversion
FROM funnel_steps;

查询结果示例

landing_users cart_users purchase_users landing_to_cart_conversion landing_to_cart_dropoff cart_to_purchase_conversion cart_to_purchase_dropoff overall_conversion
1000 200 50 20.00 80.00 25.00 75.00 5.00

如何使用这些数据?

  1. 识别最大流失点:着陆页到购物车流失 80%
  2. 优先级排序:先优化着陆页体验和商品展示
  3. 设定目标:如果将着陆页到购物车的转化率从 20% 提升到 30%,整体转化率将从 5% 提升到 7.5%
  4. A/B 测试:测试不同的着陆页设计、商品推荐算法等

实战练习:Salesforce 面试题

准备好应用漏斗分析技术了吗?试试这道 Salesforce 面试题:

Lead Conversion Funnel (Salesforce)

计算 B2B 销售漏斗每个阶段的转化率(Lead -> Opportunity -> Closed Won)。这道题挑战你计算计数和不同阶段之间的百分比流失。

问题描述

给定一个 sales_funnel 表:

lead_id stage stage_date
1 Lead 2023-01-01
1 Opportunity 2023-01-05
1 Closed Won 2023-01-10
2 Lead 2023-01-02
2 Opportunity 2023-01-06
3 Lead 2023-01-03

任务

计算每个阶段的用户数和转化率:

  • Lead 数量
  • Opportunity 数量和从 Lead 的转化率
  • Closed Won 数量和从 Opportunity 的转化率
  • 整体转化率(从 Lead 到 Closed Won)

提示

  • 使用方法 2(左连接)确保顺序
  • 计算每个阶段之间的转化率
  • 注意处理 NULL 值

扩展挑战

  • 计算每个阶段的平均转化时间
  • 按销售代表分组分析
  • 识别高转化率和低转化率的特征

结论

使用 SQL 构建漏斗可以让你对数据进行精细控制。与预构建的分析工具不同,你可以:

SQL 漏斗分析的优势

灵活性

  • 定义自定义步骤(不限于预设的漏斗)
  • 处理复杂的用户旅程(多路径、循环、回退)
  • 按数据库中的任何属性进行过滤(地区、设备、渠道等)

准确性

  • 直接访问原始数据
  • 完全控制计算逻辑
  • 可以验证和调试结果

可扩展性

  • 适用于任何规模的数据
  • 可以优化查询性能
  • 易于集成到数据管道

成本效益

  • 无需购买昂贵的分析工具
  • 利用现有的数据库基础设施
  • 易于维护和更新

学习路径

从简单的聚合开始,随着需求的增长逐步升级到有序漏斗!

初学者

  • 使用方法 1(逐步聚合)快速了解漏斗概念
  • 理解转化率和流失率的计算

中级用户

  • 使用方法 2(左连接)构建准确的有序漏斗
  • 添加时间维度分析(按周、按月)
  • 按用户属性细分(地区、设备、渠道)

高级用户

  • 使用方法 3(单查询透视)优化大数据集性能
  • 构建多路径漏斗(允许用户跳过某些步骤)
  • 实现漏斗回退分析(用户返回上一步)
  • 结合窗口函数进行时间序列分析

实际应用场景

电商平台

  • 访问 -> 浏览 -> 加购 -> 结账 -> 购买
  • 识别购物车放弃的原因
  • 优化结账流程

SaaS 产品

  • 访问 -> 注册 -> 激活 -> 订阅 -> 续费
  • 提升新用户激活率
  • 减少订阅流失

内容平台

  • 访问 -> 阅读 -> 点赞 -> 分享 -> 订阅
  • 增加用户参与度
  • 提升订阅转化率

B2B 销售

  • Lead -> Opportunity -> Proposal -> Negotiation -> Closed Won
  • 缩短销售周期
  • 提高成交率

移动应用

  • 安装 -> 注册 -> 首次使用 -> 留存 -> 付费
  • 优化新用户引导流程
  • 提升用户留存和付费转化

最佳实践

数据质量

  • 确保事件数据完整和准确
  • 处理重复事件和异常值
  • 验证时间戳的正确性

性能优化

  • 为事件表添加索引(user_id, event_name, event_time)
  • 使用分区表处理大数据量
  • 考虑物化视图缓存常用漏斗

可维护性

  • 使用 CTE 组织复杂查询
  • 添加注释说明计算逻辑
  • 版本控制漏斗定义

业务洞察

  • 定期监控漏斗变化
  • 设置转化率阈值告警
  • 结合 A/B 测试验证优化效果

相关文章推荐


本文转载自 www.hisqlboy.com

原文标题:Building Conversion Funnels in SQL

原文链接:https://www.hisqlboy.com/blog/building-conversion-funnels-in-sql

原作者:SQL Boy Team

转载日期:2026-02-12

著作权归原作者所有。本文仅用于学习交流,非商业用途。

相关推荐
丿BAIKAL巛2 小时前
Docker部署的Mysql数据库自动化备份
数据库·mysql·docker
爬山算法2 小时前
MongoDB(11)MongoDB的默认端口号是多少?
数据库·mongodb
betazhou2 小时前
Mongodb日志类型以及日志轮转
数据库·mongodb
一次旅行2 小时前
接口自动化测试模板
数据库·python·pytest
想睡hhh2 小时前
redis的高效工作方式
数据库·redis·缓存
、BeYourself2 小时前
PostgreSQL 安装中文全文检索插件zhparser扩展
数据库·postgresql·全文检索
dishugj2 小时前
【Oracle】Oracle rac1 节点ora.chad offline解决方案
数据库·oracle
木子02042 小时前
oracle里面inner join 和left join 的区别
数据库·oracle
李慕婉学姐2 小时前
【开题答辩过程】以《招聘数据分析与可视化系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
数据挖掘·数据分析