You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spark SQL如何按指定日期计算过去30天(不含)的数值总和

解决Spark SQL计算过去30天滑动总和的问题

我看你遇到的问题是用窗口函数计算每个门店商品过去30天(不含当日)的总和时,原SQL语法不对导致没得到预期结果。先帮你拆解一下问题,再给出正确的解决方案:

原SQL的问题

你的原SQL里,窗口函数的ORDER BY a.date BETWEEN ...是语法错误——窗口函数的ORDER BY只是用来指定窗口内的排序字段,窗口的范围需要单独用ROWS BETWEENRANGE BETWEEN来定义,不能直接在ORDER BY后面加条件。

正确的Spark SQL写法

Spark 2.3及以上版本支持直接用INTERVAL语法定义基于时间的滑动窗口,正好匹配你的需求。这里我们需要计算当前日期往前推30天到前1天的总和(不含当日),所以窗口范围应该是RANGE BETWEEN INTERVAL 30 DAY PRECEDING AND INTERVAL 1 DAY PRECEDING

基础版本(仅针对已有记录)

如果你的原表中已经包含所有需要的日期-门店-商品组合记录,可以直接用下面的SQL:

SELECT
  date,
  store,
  product,
  -- 计算过去30天(不含当日)的values总和
  SUM(values) OVER (
    PARTITION BY store, product  -- 按门店和商品分组
    ORDER BY date                -- 按日期排序
    RANGE BETWEEN INTERVAL 30 DAY PRECEDING AND INTERVAL 1 DAY PRECEDING
  ) AS sum_30d
FROM your_table_name;

完整版本(生成所有日期-门店-商品记录)

如果原表中存在某些日期没有对应门店商品的记录(比如2020-08-01没有Store1|Product1的条目),上面的SQL不会生成该日期的记录。这时候需要先构建日期、门店、商品的全量维度,再左连接原表,确保每个组合都有数据:

WITH date_dim AS (
  -- 生成需要的日期范围,这里以2020-06-01到2020-08-01为例
  SELECT sequence(to_date('2020-06-01'), to_date('2020-08-01'), INTERVAL 1 DAY) AS dates
  LATERAL VIEW explode(dates) AS date
),
store_product_dim AS (
  -- 获取所有唯一的门店-商品组合
  SELECT DISTINCT store, product FROM your_table_name
),
full_dim AS (
  -- 生成日期-门店-商品的全量组合
  SELECT d.date, sp.store, sp.product
  FROM date_dim d
  CROSS JOIN store_product_dim sp
),
joined_data AS (
  -- 左连接原表,没有数据的values填0
  SELECT
    fd.date,
    fd.store,
    fd.product,
    COALESCE(t.values, 0) AS values
  FROM full_dim fd
  LEFT JOIN your_table_name t 
    ON fd.date = t.date 
    AND fd.store = t.store 
    AND fd.product = t.product
)
SELECT
  date,
  store,
  product,
  SUM(values) OVER (
    PARTITION BY store, product
    ORDER BY date
    RANGE BETWEEN INTERVAL 30 DAY PRECEDING AND INTERVAL 1 DAY PRECEDING
  ) AS sum_30d
FROM joined_data
ORDER BY date, store, product;

验证示例

拿你提到的例子来说:

  • 当日期是2020-08-01时,窗口范围是2020-07-02到2020-07-31(因为8月1日减30天是7月2日,减1天是7月31日),如果这段时间内Store1|Product1的values总和是5,结果就会显示2020-08-01|Store1|Product1|5,完全符合你的预期。

内容的提问来源于stack exchange,提问作者PauloHFM

火山引擎 最新活动