【问题标题】:Open, high, low, close aggregation in BigQueryBigQuery 中的打开、高、低、关闭聚合
【发布时间】:2023-04-02 02:29:02
【问题描述】:

根据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

由于代码审查中只有六个 BigQuery 问题,我想我会在 Stack Overflow 上提问。这是最快的方法吗?我的查询中有什么无关的吗? (我不太确定 [OFFSET(0)] 是否在做任何事情。)

我在 Stack Overflow for Oracle、T-SQL 和 Postgres 上看到过这个问题,但我没有看到任何特定于 BigQuery 的内容。谢谢!

【问题讨论】:

    标签: group-by google-bigquery array-agg


    【解决方案1】:

    明显的改进是对 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
    

    【讨论】:

    • 谢谢,这是 max() 和 min() 的好地方。 EXTRACT(DATE from l)DATE(l) 在执行时间方面有什么区别吗?执行细节有所不同,因为 extract_date() 是使用 extract 时调用的函数,而 date() 是使用 date() 时调用的函数。
    • date(ts) vs extract(date from ts)?我会使用前者,因为它更容易/更快地键入和更具描述性等,因为执行时间/性能 - 我怀疑有很大的差异,如果有的话 - 很可能不是重要的 - 但真的不知道,因为它取决于BQ引擎实现细节!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 1970-01-01
    相关资源
    最近更新 更多