使用 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

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

相关推荐
归去_来兮18 小时前
拉格朗日插值算法原理及简单示例
算法·数据分析·拉格朗日插值
随风飘的云20 小时前
MySQL的慢查询优化解决思路
数据库
IvorySQL1 天前
PostgreSQL 技术日报 (3月7日)|生态更新与内核性能讨论
数据库·postgresql·开源
赵渝强老师1 天前
【赵渝强老师】金仓数据库的数据文件
数据库·国产数据库·kingbase·金仓数据库
随逸1771 天前
《Milvus向量数据库从入门到实战,手把手搭建语义检索系统》
数据库
神秘的猪头1 天前
🚀 React 开发者进阶:RAG 核心——手把手带你玩转 Milvus 向量数据库
数据库·后端·llm
IvorySQL2 天前
PostgreSQL 技术日报 (3月6日)|为什么 Ctrl-C 在 psql 里让人不安?
数据库·postgresql·开源
NineData2 天前
数据库管理工具NineData,一年进化成为数万+开发者的首选数据库工具?
运维·数据结构·数据库
IvorySQL2 天前
PostgreSQL 技术日报 (3月5日)|规划器控制力升级,内核能力再进阶
数据库·postgresql·开源