我需要计算前 4 周的平均值...
SELECT
*,
AVG(val) OVER (PARTITION BY some_identifier, day_of_week_column
ORDER BY date_column
ROW BETWEEN 4 PRECEDING AND 1 PRECEDING
)
AS preceding_4_week_average
FROM
myTable
然而,数据是“稀疏的”
在这种情况下,我的窗口函数应该回顾“4 周”而不是“4 行”。
- 缺少的日期不是一个0
,而是隐含的NULL
thing | date | dow | val | avg
1 | 2018-01-01 | 1 | 1 | NULL <= AVG({})
1 | 2018-01-08 | 1 | 2 | 1 <= AVG({1})
1 | 2018-01-15 | 1 | 3 | 1.5 <= AVG({1,2})
1 | 2018-01-22 | 1 | 4 | 2 <= AVG({1,2,3})
1 | 2018-01-29 | 1 | 5 | 2.5 <= AVG({1,2,3,4})
1 | 2018-02-12 | 1 | 7 | 4 <= AVG({3,4,5})
1 | 2018-02-19 | 1 | 8 | 5.33 <= AVG({4,5,7})
1 | 2018-02-26 | 1 | 9 | 6.66 <= AVG({5,7,8})
1 | 2018-03-05 | 1 | 10 | 8 <= AVG({7,8,9})
1 | 2018-03-12 | 1 | 11 | 11.25 <= AVG({7,8,9,10})
1 | 2018-03-19 | 1 | 12 | 9.5 <= AVG({8,9,10,11})
注:2018-02-05 没有价值
我通常会以两种方式之一来处理它......
- LEFT JOIN 加入模板以“强制”所有日期存在,并
AVG()
有效地“忽略”NULL。
这不太理想,因为“事物”的数量巨大并且构建此模板的成本很高。
SELECT
*,
AVG(mytable.val) OVER (PARTITION BY things.id, dates.dow
ORDER BY dates.date
ROW BETWEEN 4 PRECEDING AND 1 PRECEDING
)
AS preceding_4_week_average
FROM
things
CROSS JOIN
dates
LEFT JOIN
myTable
ON myTable.date = dates.date
AND myTable.id = things.id
- 不要使用窗口函数,而是使用自连接
这不太理想,因为 myTable 中有数百列,而 BigQuery 在这方面表现不佳。
SELECT
myTable.*,
AVG(hist.val) AS preceding_4_week_average
FROM
myTable
LEFT JOIN
myTable AS hist
ON hist.id = myTable.id
AND hist.date >= myTable.date - INTERVAL 28 DAYS
AND hist.date < myTable.date
GROUP BY
myTable.column1,
myTable.column2,
etc, etc
实际问题
有没有其他人有替代方案,最好使用窗口/分析函数来“回顾 4 周”而不是“回顾 4 行”?