基于本文回答
0
评论

计算销售额贡献了平台前 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 分类法(帕累托二八法则) 在业务分析中的实际应用,面试官主要考察以下能力:

  1. 窗口函数(Window Functions)的熟练度:如何使用 SUM() OVER() 同时计算全局总和与累计和(Running Total)。
  2. 边界条件处理:如何精准界定“贡献了前 80% 销售额”的商品边界。
  3. 业务逻辑理解:明确“在售商品”的过滤条件(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%)
第二步:精准定位“前 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)实现的高性能写法,在海量数据下优势极其明显。
右滑查看面试常问