计算销售额贡献了平台前 80% 的热销商品数量,占平台在售商品总数量的比例
面试真题:二八法则 - 计算平台 80% 销售额贡献的热销商品占比
1. 模拟数据
以下是平台在售商品及历史销售额数据表 product_sales:
| 商品ID (product_id) | 商品名称 (product_name) | 销售额 (sales_amount) | 是否在售 (is_on_sale) |
|---|---|---|---|
| P01 | iPhone 15 | 50000.00 | 1 |
| P02 | iPad Pro | 40000.00 | 1 |
| P03 | MacBook Air | 30000.00 | 1 |
| P04 | AirPods Pro | 15000.00 | 1 |
| P05 | Apple Watch | 10000.00 | 1 |
| P06 | Phone Case | 8000.00 | 1 |
| P07 | Charger | 4000.00 | 1 |
| P08 | Screen Protector | 2000.00 | 1 |
| P09 | OTG Cable | 1000.00 | 1 |
| P10 | Stylus Pen | 0.00 | 1 |
| P11 | Old iPhone (已下架) | 20000.00 | 0 |
2. 考察重点
这道题是经典的 ABC 分类法(帕累托二八法则) 在业务分析中的实际应用,面试官主要考察以下能力:
- 窗口函数(Window Functions)的熟练度:如何使用
SUM() OVER()同时计算全局总和与累计和(Running Total)。 - 边界条件处理:如何精准界定“贡献了前 80% 销售额”的商品边界。
- 业务逻辑理解:明确“在售商品”的过滤条件(
is_on_sale = 1),以及如何将分析拆解为“求分子(热销数)”与“求分母(总在售数)”。
3. SQL 解决方案 (以 PostgreSQL / Hive / MySQL 8.0+ 为准)
sql
WITH sales_ranked AS (
SELECT
product_id,
sales_amount,
-- 1. 计算当前商品及以上商品的历史累计销售额 (按销售额降序排列)
SUM(sales_amount) OVER (ORDER BY sales_amount DESC) AS cum_sales,
-- 2. 计算所有在售商品的总销售额
SUM(sales_amount) OVER () AS total_sales,
-- 3. 计算在售商品的总总数(作为分母)
COUNT(product_id) OVER () AS total_count
FROM product_sales
WHERE is_on_sale = 1 -- 只统计在售商品
),
hot_products AS (
SELECT
product_id,
total_count
FROM sales_ranked
-- 4. 边界判定:排除掉当前商品后,前面的累积贡献率不足 80%
-- 这样可以确保刚好让累计销售额跨过 80% 门槛的那款商品也被包含进来
WHERE (cum_sales - sales_amount) / total_sales < 0.8
)
SELECT
COUNT(product_id) AS hot_product_count, -- 热销商品数量
MAX(total_count) AS total_product_count, -- 在售商品总数
-- 5. 计算比例,转为百分比格式
ROUND(COUNT(product_id) * 1.0 / MAX(total_count) * 100, 2) || '%' AS hot_ratio
FROM hot_products;
4. 核心步骤与深度解析
第一步:过滤与窗口计算(sales_ranked 临时表)
我们首先通过 WHERE is_on_sale = 1 排除已下架商品(P11)。
在窗口函数中:
SUM(sales_amount) OVER ()计算出当前所有在售商品的总销售额为 160,000。SUM(sales_amount) OVER (ORDER BY sales_amount DESC)会随着商品销售额从大到小依次累加:- P01 累计:
50,000(占比 31.25%) - P02 累计:
90,000(占比 56.25%) - P03 累计:
120,000(占比 75.00%) - P04 累计:
135,000(占比 84.38%) —— 此时累计占比已突破 80% 阈值。 - P05 累计:
145,000(占比 90.63%)
- P01 累计:
第二步:精准定位“前 80% 销售额”的边界(hot_products 过滤)
如果单纯使用 cum_sales / total_sales <= 0.8 作为过滤条件,只能筛选出 P01、P02、P03,此时总贡献率只有 75%,还未达到 80%。为了让销售额贡献“达到” 80%,必须把使累计额跨越 80% 门槛的那个边缘商品(P04)算进去。
- 判定公式:
(cum_sales - sales_amount) / total_sales < 0.8 - 逻辑释义:当前商品之前的累积销售额占比还没到 80%。
- 对于 P04:之前累积为 120,000,占比 75%(< 80%),通过筛选。
- 对于 P05:之前累积为 135,000,占比 84.38%(>= 80%),被过滤。
- 最终筛选出的热销商品为:P01, P02, P03, P04(共 4 个)。
第三步:聚合计算占比
- 热销商品数量(
COUNT)= 4 - 总在售商品数(
MAX(total_count))= 10 - 占比结果 =
4 / 10 = 40.00%
输出结果:
| hot_product_count | total_product_count | hot_ratio |
|---|---|---|
| 4 | 10 | 40.00% |
5. 面试加分项/同行竞争优势
- 主动提及数据倾斜与并列(Ties)处理:若遇到销售额完全相同的商品,
ORDER BY sales_amount DESC会导致累计值在并列商品上出现跳跃。若业务要求严格,可向面试官说明:可在ORDER BY中加入辅助排序列(如ORDER BY sales_amount DESC, product_id)来确保累计值平滑且计算结果唯一。 - 展示对性能的考虑:在第一步的
WITH语句中,我们通过一次SELECT完成了累计求和、总和及总计数的计算。避免了多次关联(Self-Join)和子查询,这是利用窗口函数一次扫表(Single Table Scan)实现的高性能写法,在海量数据下优势极其明显。
右滑查看面试常问