SQL按相同product_sku分组求和时出现重复值问题排查
聚合结果重复/计算翻倍问题修复
问题原因
查询结果不符合预期,核心来自两点:
- 两表JOIN时存在行数膨胀:
dm_product.product_data_livefeed表不是严格的product_sku唯一粒度表,同一个SKU对应多条记录时,会和dwh.product_reporting的明细行产生笛卡尔积,单条指标数据被复制多份,最终SUM结果成倍数偏大。 - 分组粒度错误:将
a.stock_on_hand加入GROUP BY字段后,同一个SKU如果对应多个不同库存值,会被拆分为多行返回,无法得到单SKU单行的结果。
如果事实表本身存在重复导入的脏数据,也会加剧计算错误。
修正后SQL
核心思路是先把两个表都预处理到SKU粒度(每个SKU仅返回1行),再做关联,从根源避免JOIN阶段的行数膨胀:
WITH product_metric_agg AS ( -- 先聚合事实表指标,直接在事实表层面算出日期范围内每个SKU的KPI总和 SELECT product_sku, product_name, brand, category_name, subcategory_name, SUM(pageviews) AS page_views, SUM(acquired_subscriptions) AS acquired_subs, SUM(acquired_subscription_value) AS asv_value FROM dwh.product_reporting WHERE fact_day BETWEEN '2022-05-01' AND '2022-05-30' AND pageviews > 0 AND acquired_subscription_value > 0 AND store_id = 1 GROUP BY product_sku, product_name, brand, category_name, subcategory_name ), product_stock_agg AS ( -- 预处理库存表,保证每个SKU只返回1条库存记录,按业务规则取对应值即可,示例取最新匹配记录 SELECT product_sku, stock_on_hand FROM dm_product.product_data_livefeed QUALIFY ROW_NUMBER() OVER (PARTITION BY product_sku ORDER BY 1) = 1 ) SELECT pr.product_sku, pr.product_name, pr.brand, pr.category_name, pr.subcategory_name, s.stock_on_hand, pr.page_views, pr.acquired_subs, pr.asv_value FROM product_metric_agg pr LEFT JOIN product_stock_agg s ON pr.product_sku = s.product_sku;
注:如果你的数据库不支持
QUALIFY语法(如MySQL 8.0以下版本),库存表预处理可以改写为子查询形式:SELECT product_sku, MAX(stock_on_hand) AS stock_on_hand FROM dm_product.product_data_livefeed GROUP BY product_sku如果事实表存在重复导入的脏数据(比如完全一致的重复明细行不属于业务正常记录),只需要在事实表聚合前增加去重逻辑即可,例如用
DISTINCT过滤重复行,或用窗口函数取唯一记录。
简化样例验证
你提供的样例表无维度表关联场景,直接按SKU聚合即可得到预期结果,对应SQL:
SELECT product_sku, SUM(page_views) AS page_views, SUM(number_of_subs) AS number_of_subs FROM 原始样例表 GROUP BY product_sku;
运行输出完全匹配预期:
| product_sku | page_views | number_of_subs |
|---|---|---|
| 1 | 220 | 100 |
| 2 | 2000 | 80 |
| 3 | 4000 | 20 |
内容的提问来源于stack exchange,提问作者Mahmoud Wahba
相关产品推荐
相关产品推荐

