Sql 如何通过设置累积和的限制来表分区?

Sql 如何通过设置累积和的限制来表分区?,sql,postgresql,google-bigquery,Sql,Postgresql,Google Bigquery,我在BigQuery中有一个包含一些数据的表。 我想找到value1、value2和value3的总和,这些总和使用总和value3的总和限制进行分组。在示例中,我将总和限制设置为60 我知道如何分组排序、筛选和查找总和,但我不知道如何像这样分组表值(步骤2)。 似乎我需要为每个字段逐行查找累积和,并在value3的累积和超过我的限制时停止进程。然后重新开始 如何在BigQuery中创建它?下面是针对BigQuery标准SQL的 根据OP的评论-我将使用此部分作为窗口函数。每个窗口将有30-2

我在BigQuery中有一个包含一些数据的表。 我想找到value1、value2和value3的总和,这些总和使用总和value3的总和限制进行分组。在示例中,我将总和限制设置为60

我知道如何分组排序、筛选和查找总和,但我不知道如何像这样分组表值(步骤2)。 似乎我需要为每个字段逐行查找累积和,并在value3的累积和超过我的限制时停止进程。然后重新开始


如何在BigQuery中创建它?

下面是针对BigQuery标准SQL的

根据OP的评论-我将使用此部分作为窗口函数。每个窗口将有30-200行

示例数据仅代表一个分区/窗口的示例-因此我添加了
id
列来扮演分区的角色,因此代码可以应用于实际用例(只需用实际的相应列名替换
id

--

结果

简要说明

实际上,在上述解决方案中,很少有不同的逻辑部分

第1部分:[最复杂部分]按值之和进行分组3-使其小于或等于某个值(本例中为60)

主要逻辑在JS UDF中通过以下逻辑实现(仅主要步骤):

  • 计算分区/组的初始数量-
    N
  • 使用前N行中的N个元素初始化数组值3
  • 循环遍历value3的其余部分,并在每次迭代中使用min sum将其添加到组中,直到该值超过限制(组中只有value3的情况除外)
  • 如果超过上述#3中的总和限制-递增计数-
    N+1
    并使用新的组数重复上述#2,3
  • 在处理##1-4的过程中,所有相应的位置都保持原封不动的值3,这样就可以将其合并回第2部分中的初始数据
  • 结果在
    按值3分组的CTE中捕获,如下所示

    第2部分:将分组信息(来自第1部分)连接回主数据(注意添加到主数据的位置,因此这里使用带位置的数据)

    结果被捕获在带有组的所有值中,如下所示

    第3部分:最终汇总-结果已显示在答案的顶部:o)

    测试

    作为光测试的一部分——我使用很少的虚拟数据运行这个解决方案——下面就是其中之一

    WITH `project.dataset.table` AS (
      SELECT 1 id, 6854 value1, 10 value2, 83 value3 UNION ALL
      SELECT 1, 6723, 9, 82 UNION ALL
      SELECT 1, 2234, 203, 49 UNION ALL
      SELECT 1, 456, 1888, 48 UNION ALL
      SELECT 1, 434, 679, 33 UNION ALL
      SELECT 1, 789, 234, 32 UNION ALL
      SELECT 1, 678, 11, 26 UNION ALL
      SELECT 1, 345, 33, 19 UNION ALL
      SELECT 1, 22, 345, 19 UNION ALL
      SELECT 1, 232, 45, 17 UNION ALL
      SELECT 1, 234, 4, 15 UNION ALL
      SELECT 1, 45, 123, 13 UNION ALL
      SELECT 1, 4, 123, 11 UNION ALL
      SELECT 1, 123, 2, 11 UNION ALL
      SELECT 1, 23, 76, 10 UNION ALL
      SELECT 1, 34, 23, 8 UNION ALL
      SELECT 1, 12, 45, 8 UNION ALL
      SELECT 1, 23, 30, 7 UNION ALL
      SELECT 1, 23, 2, 5 UNION ALL
      SELECT 1, 12, 4, 4 UNION ALL
      SELECT 2, 2, 50, 45 UNION ALL
      SELECT 2, 2, 50, 45 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 3, 2, 50, 5 UNION ALL
      SELECT 3, 2, 50, 5 UNION ALL
      SELECT 3, 3, 60, 5 UNION ALL
      SELECT 3, 3, 60, 85 UNION ALL
      SELECT 3, 3, 60, 45 UNION ALL
      SELECT 4, 2, 50, 25 UNION ALL
      SELECT 4, 2, 50, 25 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24
    )
    
    下面是输出


    这是一个有趣的用例。你能澄清一下吗?你是否有任何额外的要求,例如,为了优化目的,尽可能密集地填充每个组。或者您只想按照值3的降序排列,因为在您的示例中,最好尽可能密集地填充每个组。我只想得到每个组的值1和值2的和,得到了,所以在你们的例子中,值3的顺序并不重要,可以改变。好的,是的!我知道如何使用JavaScript和带有continue语句的循环来实现它。但是不知道如何在BigQueryOne中重复它还有一个问题-你的桌子上有多少行?哇!!!非常感谢。这有点复杂,是吗?)(稍微):考虑一下投票,接受它,如果它对你有用的话,我如何修改代码以获得最小可能的值,然后再加上大小?很难在评论中提出任何建议-请用所有相关的细节发布新的问题-我很乐意帮助你。
    WITH `project.dataset.table` AS (
      SELECT 1 id, 6854 value1, 10 value2, 83 value3 UNION ALL
      SELECT 1, 6723, 9, 82 UNION ALL
      SELECT 1, 2234, 203, 49 UNION ALL
      SELECT 1, 456, 1888, 48 UNION ALL
      SELECT 1, 434, 679, 33 UNION ALL
      SELECT 1, 789, 234, 32 UNION ALL
      SELECT 1, 678, 11, 26 UNION ALL
      SELECT 1, 345, 33, 19 UNION ALL
      SELECT 1, 22, 345, 19 UNION ALL
      SELECT 1, 232, 45, 17 UNION ALL
      SELECT 1, 234, 4, 15 UNION ALL
      SELECT 1, 45, 123, 13 UNION ALL
      SELECT 1, 4, 123, 11 UNION ALL
      SELECT 1, 123, 2, 11 UNION ALL
      SELECT 1, 23, 76, 10 UNION ALL
      SELECT 1, 34, 23, 8 UNION ALL
      SELECT 1, 12, 45, 8 UNION ALL
      SELECT 1, 23, 30, 7 UNION ALL
      SELECT 1, 23, 2, 5 UNION ALL
      SELECT 1, 12, 4, 4 
    ),     
    
      data_with_positions as ( 
      -- adding position number to distinguish same values in different rows
      -- for example two 19s and two 11s in sample data
      SELECT *, ROW_NUMBER() OVER(PARTITION BY id) pos
      FROM `project.dataset.table`
    ), grouped_by_value3 AS (
      -- grouping value3 (along with their respective id, pos) based on summation
      SELECT id, 
        CAST(SPLIT(line)[OFFSET(0)] AS INT64) pos,
        CAST(SPLIT(line)[OFFSET(1)] AS INT64) value3,
        group_id
      FROM (
        SELECT id, ROW_NUMBER() OVER(PARTITION BY id) group_id, grp    
        FROM (
          SELECT id, 
            partitionBySum(ARRAY_AGG(STRUCT(CAST(value3 AS FLOAT64), CAST(pos AS FLOAT64) ) ORDER BY value3 DESC), 60) arr
          FROM data_with_positions GROUP BY id
        ), UNNEST(arr) grp
      ), UNNEST(SPLIT(grp, ';')) line
    ), all_values_with_groups AS (
      -- join grouping info back to data 
      SELECT id, pos, value1, value2, value3, group_id
      FROM data_with_positions
      JOIN grouped_by_value3 USING(id, pos, value3)
    )
    SELECT id, group_id,
      STRING_AGG(CAST(value1 AS STRING) ORDER BY value3 DESC) list_values1,
      STRING_AGG(CAST(value2 AS STRING) ORDER BY value3 DESC) list_values2,
      STRING_AGG(CAST(value3 AS STRING) ORDER BY value3 DESC) list_values3,
      SUM(value1) sum_values1,
      SUM(value2) sum_values2,
      SUM(value3) sum_values3,
    FROM all_values_with_groups
    GROUP BY id, group_id ORDER BY id, group_id    
    
    WITH `project.dataset.table` AS (
      SELECT 1 id, 6854 value1, 10 value2, 83 value3 UNION ALL
      SELECT 1, 6723, 9, 82 UNION ALL
      SELECT 1, 2234, 203, 49 UNION ALL
      SELECT 1, 456, 1888, 48 UNION ALL
      SELECT 1, 434, 679, 33 UNION ALL
      SELECT 1, 789, 234, 32 UNION ALL
      SELECT 1, 678, 11, 26 UNION ALL
      SELECT 1, 345, 33, 19 UNION ALL
      SELECT 1, 22, 345, 19 UNION ALL
      SELECT 1, 232, 45, 17 UNION ALL
      SELECT 1, 234, 4, 15 UNION ALL
      SELECT 1, 45, 123, 13 UNION ALL
      SELECT 1, 4, 123, 11 UNION ALL
      SELECT 1, 123, 2, 11 UNION ALL
      SELECT 1, 23, 76, 10 UNION ALL
      SELECT 1, 34, 23, 8 UNION ALL
      SELECT 1, 12, 45, 8 UNION ALL
      SELECT 1, 23, 30, 7 UNION ALL
      SELECT 1, 23, 2, 5 UNION ALL
      SELECT 1, 12, 4, 4 UNION ALL
      SELECT 2, 2, 50, 45 UNION ALL
      SELECT 2, 2, 50, 45 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 2, 3, 60, 44 UNION ALL
      SELECT 3, 2, 50, 5 UNION ALL
      SELECT 3, 2, 50, 5 UNION ALL
      SELECT 3, 3, 60, 5 UNION ALL
      SELECT 3, 3, 60, 85 UNION ALL
      SELECT 3, 3, 60, 45 UNION ALL
      SELECT 4, 2, 50, 25 UNION ALL
      SELECT 4, 2, 50, 25 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24 UNION ALL
      SELECT 4, 3, 60, 24
    )