BigQuery 中的开放、高、低、关闭聚合
Open, high, low, close aggregation in BigQuery
基于 using ARRAY_AGG()
to obtain the latest record 的 BigQuery 最佳实践,以下是我获取某字段一天的第一个、最后一个最小值和最大值的方法。数据大约每小时报告一次。
WITH t AS (
SELECT TIMESTAMP('2021-01-01 01:00:00') as l, 10 as v
UNION ALL
SELECT TIMESTAMP('2021-01-01 02:00:00') as l, 12 as v
UNION ALL
SELECT TIMESTAMP('2021-01-01 03:00:00') as l, 15 as v
UNION ALL
SELECT TIMESTAMP('2021-01-01 04:00:00') as l, 2 as v
UNION ALL
SELECT TIMESTAMP('2021-01-02 01:00:00') as l, 600 as v
UNION ALL
SELECT TIMESTAMP('2021-01-02 02:00:00') as l, 120 as v
UNION ALL
SELECT TIMESTAMP('2021-01-02 03:00:00') as l, 150 as v
UNION ALL
SELECT TIMESTAMP('2021-01-03 04:00:00') as l, 0 as v)
SELECT EXTRACT(DATE FROM l) d,
ARRAY_AGG(t.v ORDER BY t.l ASC LIMIT 1)[OFFSET(0)] first_value,
ARRAY_AGG(t.v ORDER BY t.l DESC LIMIT 1)[OFFSET(0)] last_value,
ARRAY_AGG(t.v ORDER BY t.v DESC LIMIT 1)[OFFSET(0)] max_value,
ARRAY_AGG(t.v ORDER BY t.v ASC LIMIT 1)[OFFSET(0)] min_value,
FROM
t
GROUP BY
d
输出:
Row
d
max_value
min_value
last_value
first_value
1
2021-01-01
15
2
2
10
2
2021-01-02
600
120
150
600
3
2021-01-03
0
0
0
0
由于 Code Review 上只有六个 BigQuery 问题,我想我应该在主 Stack Overflow 上提问。这是最快的方法吗?我的查询中有什么无关的东西吗? (我不太确定 [OFFSET(0)] 正在做任何事情。)
我在针对 Oracle、T-SQL 和 Postgres 的 Stack Overflow 上看到过这个问题,但我没有看到任何特定于 BigQuery 的问题。谢谢!
明显的改进是对 min_value 和 max_value
使用简单的 MIN 和 MAX
select date(l) d,
array_agg(v order by l asc limit 1)[offset(0)] first_value,
array_agg(v order by l desc limit 1)[offset(0)] last_value,
max(v) max_value,
min(v) min_value
from t
group by d
而不是这个,在这里使用 array_agg 是一个很好的做法,在这里使用 [offset(0)]
很重要,因为没有它 - 你的输出将是只有一个元素的数组 - 但你很可能想要元素自己出去
还有一个 - 取决于您的数据量 - 您可以尝试以下使用分析聚合函数与仅使用聚合函数的方法
select distinct * from (
select date(l) d,
first_value(v) over(partition by date(l) order by l asc) first_value,
first_value(v) over(partition by date(l) order by l desc) last_value,
max(v) over(partition by date(l)) max_value,
min(v) over(partition by date(l)) min_value
from t
)
需要考虑的更多选项 - 使用如下示例中的近似聚合函数
select extract(date from l) d,
approx_top_sum(v, 1 / unix_seconds(l), 1)[offset(0)].value first_value,
approx_top_sum(v, unix_seconds(l), 1)[offset(0)].value last_value,
max(v) max_value,
min(v) min_value,
from t
group by d
基于 using ARRAY_AGG()
to obtain the latest record 的 BigQuery 最佳实践,以下是我获取某字段一天的第一个、最后一个最小值和最大值的方法。数据大约每小时报告一次。
WITH t AS (
SELECT TIMESTAMP('2021-01-01 01:00:00') as l, 10 as v
UNION ALL
SELECT TIMESTAMP('2021-01-01 02:00:00') as l, 12 as v
UNION ALL
SELECT TIMESTAMP('2021-01-01 03:00:00') as l, 15 as v
UNION ALL
SELECT TIMESTAMP('2021-01-01 04:00:00') as l, 2 as v
UNION ALL
SELECT TIMESTAMP('2021-01-02 01:00:00') as l, 600 as v
UNION ALL
SELECT TIMESTAMP('2021-01-02 02:00:00') as l, 120 as v
UNION ALL
SELECT TIMESTAMP('2021-01-02 03:00:00') as l, 150 as v
UNION ALL
SELECT TIMESTAMP('2021-01-03 04:00:00') as l, 0 as v)
SELECT EXTRACT(DATE FROM l) d,
ARRAY_AGG(t.v ORDER BY t.l ASC LIMIT 1)[OFFSET(0)] first_value,
ARRAY_AGG(t.v ORDER BY t.l DESC LIMIT 1)[OFFSET(0)] last_value,
ARRAY_AGG(t.v ORDER BY t.v DESC LIMIT 1)[OFFSET(0)] max_value,
ARRAY_AGG(t.v ORDER BY t.v ASC LIMIT 1)[OFFSET(0)] min_value,
FROM
t
GROUP BY
d
输出:
Row | d | max_value | min_value | last_value | first_value |
---|---|---|---|---|---|
1 | 2021-01-01 | 15 | 2 | 2 | 10 |
2 | 2021-01-02 | 600 | 120 | 150 | 600 |
3 | 2021-01-03 | 0 | 0 | 0 | 0 |
由于 Code Review 上只有六个 BigQuery 问题,我想我应该在主 Stack Overflow 上提问。这是最快的方法吗?我的查询中有什么无关的东西吗? (我不太确定 [OFFSET(0)] 正在做任何事情。)
我在针对 Oracle、T-SQL 和 Postgres 的 Stack Overflow 上看到过这个问题,但我没有看到任何特定于 BigQuery 的问题。谢谢!
明显的改进是对 min_value 和 max_value
使用简单的 MIN 和 MAXselect date(l) d,
array_agg(v order by l asc limit 1)[offset(0)] first_value,
array_agg(v order by l desc limit 1)[offset(0)] last_value,
max(v) max_value,
min(v) min_value
from t
group by d
而不是这个,在这里使用 array_agg 是一个很好的做法,在这里使用 [offset(0)]
很重要,因为没有它 - 你的输出将是只有一个元素的数组 - 但你很可能想要元素自己出去
还有一个 - 取决于您的数据量 - 您可以尝试以下使用分析聚合函数与仅使用聚合函数的方法
select distinct * from (
select date(l) d,
first_value(v) over(partition by date(l) order by l asc) first_value,
first_value(v) over(partition by date(l) order by l desc) last_value,
max(v) over(partition by date(l)) max_value,
min(v) over(partition by date(l)) min_value
from t
)
需要考虑的更多选项 - 使用如下示例中的近似聚合函数
select extract(date from l) d,
approx_top_sum(v, 1 / unix_seconds(l), 1)[offset(0)].value first_value,
approx_top_sum(v, unix_seconds(l), 1)[offset(0)].value last_value,
max(v) max_value,
min(v) min_value,
from t
group by d