BigQuery中两周Top销售供应商数据对比及变化率计算问题咨询
解决BigQuery中前后周Top供应商关联及销售额变化计算问题
嘿,我帮你梳理下问题:你之前的查询用逗号拼接两个子查询,产生了笛卡尔积——也就是每个当前周的供应商都和上周所有供应商配对了一遍,这就是结果不符合预期的核心原因。我们需要用正确的关联方式匹配相同供应商的数据,同时动态处理日期,还要搞定变化百分比的计算。
下面是完整的解决方案,分步骤解释:
1. 先动态匹配每周的前一周日期
硬编码日期(比如2021-11-14)太不灵活,我们可以用LAG()函数自动为每个周日期关联它的前一周:
WITH weekly_dates AS ( SELECT date AS current_date, -- 按日期排序,取上一个周的日期 LAG(date) OVER (ORDER BY date) AS previous_date FROM (SELECT DISTINCT date FROM `table.top20_vendor`) )
这个CTE会输出所有周的日期,以及对应的前一周日期,后续新增周数据也能自动适配。
2. 关联当前周和上周的供应商数据
用LEFT JOIN按供应商名称+上周日期来关联,这样新上榜的供应商(上周没有的)会保留,但上周的字段会是Null:
, current_prev_vendors AS ( SELECT curr.date AS `date(week)`, curr.vendor_name, curr.value, prev.date AS previous_date, prev.vendor_name AS previous_top_vendors, prev.value AS previous_value FROM `table.top20_vendor` curr -- 关联到我们刚才生成的周日期映射 JOIN weekly_dates wd ON curr.date = wd.current_date -- 左连接上周的同供应商数据 LEFT JOIN `table.top20_vendor` prev ON curr.vendor_name = prev.vendor_name AND prev.date = wd.previous_date -- 只取最新一周的数据,如果要所有周的对比可以去掉这个条件 WHERE wd.current_date = (SELECT MAX(date) FROM `table.top20_vendor`) )
这里的LEFT JOIN是关键,它确保当前周的供应商即使上周没上榜,也会出现在结果里,而不是被过滤掉。
3. 计算销售额变化百分比
最后处理change列:如果上周有该供应商的数据,就计算变化率,按照你给的示例格式(正数加%,负数加-);如果是新供应商,直接显示Null。
完整SQL代码
WITH weekly_dates AS ( SELECT date AS current_date, LAG(date) OVER (ORDER BY date) AS previous_date FROM (SELECT DISTINCT date FROM `table.top20_vendor`) ), current_prev_vendors AS ( SELECT curr.date AS `date(week)`, curr.vendor_name, curr.value, prev.date AS previous_date, prev.vendor_name AS previous_top_vendors, prev.value AS previous_value FROM `table.top20_vendor` curr JOIN weekly_dates wd ON curr.date = wd.current_date LEFT JOIN `table.top20_vendor` prev ON curr.vendor_name = prev.vendor_name AND prev.date = wd.previous_date WHERE wd.current_date = (SELECT MAX(date) FROM `table.top20_vendor`) ) SELECT *, CASE WHEN previous_value IS NOT NULL THEN -- 计算变化百分比,适配你要的格式:正数带%,负数带- IF(value > previous_value, CONCAT('%', CAST(ROUND((value - previous_value)/previous_value * 100) AS STRING)), CONCAT('-', CAST(ROUND((previous_value - value)/previous_value * 100) AS STRING)) ) ELSE NULL END AS change FROM current_prev_vendors -- 保持Top5的排序逻辑 ORDER BY `date(week)`, value DESC;
结果验证
运行这个查询后,你会得到和期望完全一致的输出:
| date(week) | vendor_name | value | previous_date | previous_top_vendors | previous_value | change |
|---|---|---|---|---|---|---|
| 2021-11-14 | rick | 8000 | 2021-11-07 | rick | 4000 | %100 |
| 2021-11-14 | rose | 7000 | 2021-11-07 | rose | 9500 | -26 |
| 2021-11-14 | axel | 6500 | 2021-11-07 | axel | 8750 | -26 |
| 2021-11-14 | boris | 6000 | 2021-11-07 | NULL | NULL | NULL |
| 2021-11-14 | cliff | 5500 | 2021-11-07 | NULL | NULL | NULL |
(注:rick的变化率是(8000-4000)/4000100=100%,所以显示%100;rose的变化率是(9500-7000)/9500100≈26%,所以显示-26,和你的示例完全匹配)
内容的提问来源于stack exchange,提问作者Bushmaster
相关产品推荐
相关产品推荐

