【问题标题】:Combining aggregate and analytics functions in BigQuery to reduce table size在 BigQuery 中结合聚合和分析功能以减小表大小
【发布时间】:2021-02-07 22:33:05
【问题描述】:

我面临的问题更多是关于查询设计而不是 SQL 细节。本质上,我试图通过执行下面描述的以下转换来减小数据集大小。

我从电压测量的不规则采样时间序列开始:

Seconds Volts
0.1 2899
0.15 2999
0.17 2990
0.6 3001
0.98 2978
1.2 3000
1.22 3003
3.7 2888
4.1 2900
4.11 3012
4.7 3000
4.8 3000

我将数据分到桶中,彼此靠近的数据点落入同一个桶中。在此示例中,我只需将 Seconds 列除以 1 即可将数据放入 1 秒的存储桶中。我还为每个组添加了一个排序号。我使用以下查询:

WITH qry1 AS (SELECT 
  Seconds
  , Volts
  , DIV(CAST(Seconds AS NUMERIC), 1) as BinNo
  , Rank() OVER (PARTITION BY DIV(CAST(Seconds AS NUMERIC), 1) ORDER BY Seconds) as BinRank
FROM
  project.rawdata
)
Seconds Volts BinNo BinRank
0.1 2899 0 1
0.15 2999 0 2
0.17 2990 0 3
0.6 3001 0 4
0.98 2978 0 5
1.2 3000 1 1
1.22 3003 1 2
3.7 2888 3 1
4.1 2900 4 1
4.11 3012 4 2
4.7 3000 4 3
4.8 3000 4 4

现在是我苦苦挣扎的部分。我正在尝试从作用于上表的查询中获取以下输出。保持时间顺序很重要,因为我需要在折线图上绘制这些值。对于每个组:

  • 获取第一行('first'表示最早的第二个值)
  • 获取 Volts 字段的最大值和最小值,并将它们与最早的(我猜也可以是最新的)秒值相关联
  • 获取最后一行(last表示最新​​的Second值)

这个查询的条件是:

  • 如果组中只有一行,只需将该行的 Volts 值同时指定为最大值和最小值,并仅对该组使用单个 Seconds 值
  • 如果组中只有两行,只需将最大值和最小值的 Volts 值分别分配给对应的第一个和最后一个 Seconds 值。
  • (现在对于我正在努力的部分)如果每个组有三行或更多行,请如上所述提取第一行和最后一行,然后还要获取组中所有行的最大值和最小值并将它们分配给第一行和最后一行之间的中间行的最大值和最小值。输出如下。如前所述,此步骤可以与第一个和最后一个 Seconds 值之间的任何位置相关联,这里我已将其分配给每个组的第一个 Seconds 值。
Seconds Volts_min Volts_max OrderingCol
0.1 2899 2899 1
0.1 2899 3001 2
0.98 2978 2978 3
1.2 3000 3000 1
1.22 3003 3003 2
3.7 2888 2888 1
4.1 2900 2900 1
4.1 2900 3012 2
4.8 3000 3000 3

这将允许我使用我们拥有的自定义图表库来绘制这些值,而不会导致内存过载。我可以使用分析函数提取每组的第一行和最后一行,然后进行连接,但无法获取中间值。排序列的目标是让我能够在将数据拉到仪表板之前对表进行排序。我正在尝试在 BigQuery 中执行此操作作为首选。

谢谢:)

【问题讨论】:

    标签: sql google-bigquery


    【解决方案1】:

    下面应该这样做

    select Seconds, values.*, 
      row_number() over(partition by bin_num order by Seconds) as OrderingCol
    from (
      select *,
        case
          when row_num = 1 or row_num = rows_count then true
          when rows_count > 2 and row_num = 2 then true
        end toShow,
        case 
          when row_num = 1 then struct(first_row.Volts as Volts_min, first_row.Volts as Volts_max)
          when row_num = rows_count then struct(last_row.Volts as Volts_min, last_row.Volts as Volts_max)
          else struct(min_val as Volts_min, max_val as Volts_max)
        end values
      from (
        select *,
          div(cast(Seconds AS numeric), 1) as bin_num,
          row_number() over win_all as row_num, 
          count(1) over win_all as rows_count, 
          min(Volts) over win_all as min_val, 
          max(Volts) over win_all as max_val, 
          first_value(t) over win_with_order as first_row,
          last_value(t) over win_with_order as last_row
        from `project.dataset.table` t
        window 
          win_all as (partition by div(cast(Seconds AS numeric), 1)),
          win_with_order as (partition by div(cast(Seconds AS numeric), 1) order by Seconds)
      )
    )
    where toShow
    # order by Seconds                     
    

    如果应用于您问题中的样本数据 - 输出是

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 2021-07-26
      • 2012-06-20
      • 2021-01-04
      • 1970-01-01
      • 1970-01-01
      • 2010-11-13
      相关资源
      最近更新 更多