28天滑动窗口聚合的BigQuery SQL(不写28行SQL)
Posted
技术标签:
【中文标题】28天滑动窗口聚合的BigQuery SQL(不写28行SQL)【英文标题】:BigQuery SQL for 28-day sliding window aggregate (without writing 28 lines of SQL) 【发布时间】:2015-02-17 21:49:55 【问题描述】:我正在尝试使用 LAG 函数在 BigQuery 中计算 28 天的移动总和。
这个问题的最佳答案
Bigquery SQL for sliding window aggregate
Felipe Hoffa 指出您可以使用 LAG 功能。这方面的一个例子是:
SELECT
spend + spend_lagged_1day + spend_lagged_2day + spend_lagged_3day + ... + spend_lagged_27day as spend_28_day_sum,
user,
date
FROM (
SELECT spend,
LAG(spend, 1) OVER (PARTITION BY user ORDER BY date) spend_lagged_1day,
LAG(spend, 2) OVER (PARTITION BY user ORDER BY date) spend_lagged_2day,
LAG(spend, 3) OVER (PARTITION BY user ORDER BY date) spend_lagged_3day,
...
LAG(spend, 28) OVER (PARTITION BY user ORDER BY date) spend_lagged_day,
user,
date
FROM user_spend
)
有没有办法不用写出 28 行 SQL 来做到这一点!
【问题讨论】:
【参考方案1】:BigQuery 文档没有很好地解释该工具支持的窗口函数的复杂性,因为它没有指定 ROWS 或 RANGE 之后可以出现哪些表达式。它实际上支持窗口函数的 SQL 2003 标准,您可以在网络上的其他地方找到文档,例如 here。
这意味着您可以使用单个窗口函数获得所需的效果。范围是 27,因为它是当前行之前要包含在总和中的行数。
SELECT spend,
SUM(spend) OVER (PARTITION BY user ORDER BY date ROWS BETWEEN 27 PRECEDING AND CURRENT ROW),
user,
date
FROM user_spend;
RANGE 界限也非常有用。如果您的表缺少某些用户的日期,那么 27 个 PRECEDING 行将返回超过 27 天,但 RANGE 将根据日期值本身生成一个窗口。在以下查询中,日期字段是 BigQuery TIMESTAMP,范围以微秒为单位指定。我建议,每当您在 BigQuery 中进行这样的日期数学运算时,都要对其进行彻底测试,以确保它能够为您提供预期的答案。
SELECT spend,
SUM(spend) OVER (PARTITION BY user ORDER BY date RANGE BETWEEN 27 * 24 * 60 * 60 * 1000000 PRECEDING AND CURRENT ROW),
user,
date
FROM user_spend;
【讨论】:
【参考方案2】:Bigquery:如何在窗口子句中获取滚动时间范围.....
这是一个旧帖子,但我花了很长时间寻找解决方案,并且这个帖子出现了,所以也许这会对某人有所帮助。
如果你的window子句的分区没有每天的记录,你需要使用RANGE子句来准确得到一个滚动时间范围,(ROWS会搜索数字记录,这会走得太远,因为您的 PARTITION BY 中没有每天的记录)。问题是 Bigquery RANGE 子句不支持日期。
来自 BigQuery 的文档:
numeric_expression 必须是数字类型。当前不支持 DATE 和 TIMESTAMP。此外,numeric_expression 必须是常量、非负整数或参数。
我发现的解决方法是在 ORDER BY 子句中使用 UNIX_DATE(date_expression) 和 RANGE 子句:
SUM(value) OVER (PARTITION BY Column1 ORDER BY UNIX_DATE(Date) RANGE BETWEEN 5 PRECEDING AND CURRENT ROW
【讨论】:
非常有帮助,谢谢!没有考虑使用 UNIX_DATE() 函数对 DATE 字段进行 RANGE 查询。我希望 BigQuery 在 RANGE 子句中原生支持 DATE!我想回到 3 个月,我必须用 UNIX_RANGE 大约 90 天 UNIX_DATE() 在大查询中可以解决这个问题,谢谢!【参考方案3】:这是我发现灵活有效的替代方法:
WITH users AS
(SELECT 'Isabella' as user, 1 as spend, DATE(2020, 03, 28) as date
UNION ALL SELECT 'Isabella', 2, DATE(2020, 03, 29)
UNION ALL SELECT 'Daniel', 3, DATE(2020, 03, 24)
UNION ALL SELECT 'Andrew', 4, DATE(2020, 03, 23)
UNION ALL SELECT 'Daniel', 5, DATE(2020, 03, 11)
UNION ALL SELECT 'Jose', 6, DATE(2020, 03, 17))
SELECT
user,
max(sum(case date_diff(date(2020,04,15), date, day) between 0 and 28
when true then spend else 0 end)) over(partition by user) as spend_28_day_sum
FROM users
group by user
+------------------------------+
| user | spend_28_day_sum |
+------------------------------+
| Andrew | 4 |
| Daniel | 3 |
| Isabella | 3 |
| Jose | 0 |
+------------------------------+
您可以将“窗口函数”的指定日期更改为current_date()
或cross join
,并使用generated date array 来查看用户随时间的变化。
【讨论】:
【参考方案4】:我找到了一种简洁优雅的方法来做到这一点,即使您在过去几天丢失了数据。
SELECT spend,
SUM(spend) OVER (PARTITION BY user ORDER BY UNIX_DATE(date) RANGE BETWEEN 27 PRECEDING AND CURRENT ROW),
user,
date
FROM user_spend;
UNIX_DATE()
返回自 1970 年 1 月 1 日以来的天数,因此我们可以将它与 RANGE()
函数结合使用,轻松计算返回的天数。
【讨论】:
以上是关于28天滑动窗口聚合的BigQuery SQL(不写28行SQL)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SQL Server 中的滑动窗口上聚合(计算不同的项目)?
Leetcode刷题100天—28. 实现 strStr()( 滑动窗口)—day91
Leetcode刷题100天—28. 实现 strStr()( 滑动窗口)—day91