【问题标题】:Grouping consecutive records对连续记录进行分组
【发布时间】:2017-04-04 18:43:30
【问题描述】:

这是我的记录(输入)。 field2 总是从 100 开始,之后它可以取任何大于 100 的值。

field1   field2
===============
val1     100
val2     110
------------
val3     100
val4     110
val3     130
val3     140
------------
val1     100

我需要对以 100 开头的连续记录进行分组,之后它可以是任何非 100 的数字。对于上面的示例,我需要的输出是

field 1                    field2
===================================================
(val1, val2)                (100, 110)
(val3, val4, val3, val3)    (100, 110, 130, 140)
(val1)                      (100)

我如何实现这一目标

【问题讨论】:

  • 定义连续
  • (1) 我删除了 MySQL 标签。这似乎比 BQ 更意外。 (2) SQL 表代表无序集合。您需要一个指定顺序的列。

标签: sql google-bigquery


【解决方案1】:

让我假设您有一个指定排序的列。然后您可以通过计算每条记录之前的“100”条记录的数量来识别组,然后使用array_agg()

select array_agg(field1 order by id) as field1s,
       array_agg(field2 order by id) as field2s
from (select t.*,
             sum(case when field2 = 100 then 1 else 0 end) over (order by id) as grp
      from t
     ) t
group by grp;

注意:MySQL 中的解决方案看起来非常非常不同。但是,它仍然以select 开头。

【讨论】:

  • 可能是我太天真了。我想知道我要使用的订单字段应该是什么。正如问题(input)中给出的那样,这些是我在运行选择查询时获取记录的顺序,我想根据该顺序对记录进行分组。想知道这是否可能(不使用订单列)?
  • @Raj 。 . .这是你的数据。我不知道该使用什么字段。但是如果你没有一个,那么你就不能做你想做的事。您的逻辑需要对记录进行排序。
【解决方案2】:

您必须有一些可用于定义订单的字段。
在下面的示例中,我假设它是id 字段

下面应该做你所期望的

#standardSQL
SELECT 
  CONCAT('(',STRING_AGG(field1 ORDER BY id), ')') AS field1,
  CONCAT('(',STRING_AGG(CAST(field2 AS STRING) ORDER BY id), ')') AS field2
FROM (
  SELECT 
    id, field1, field2,
    COUNTIF(field2 = 100) OVER (ORDER BY id) AS grp
  FROM yourTable
) t
GROUP BY grp
ORDER BY MIN(id)   

您可以使用以下来自您问题的虚拟数据进行测试/尝试

#standardSQL
WITH yourTable AS (
  SELECT 1 AS id, 'val1' AS field1, 100 AS field2 UNION ALL
  SELECT 2 AS id, 'val2' AS field1, 110 AS field2 UNION ALL
  SELECT 3 AS id, 'val3' AS field1, 100 AS field2 UNION ALL
  SELECT 4 AS id, 'val4' AS field1, 110 AS field2 UNION ALL
  SELECT 5 AS id, 'val3' AS field1, 130 AS field2 UNION ALL
  SELECT 6 AS id, 'val3' AS field1, 140 AS field2 UNION ALL
  SELECT 7 AS id, 'val1' AS field1, 100 AS field2 
)
SELECT 
  CONCAT('(',STRING_AGG(field1 ORDER BY id), ')') AS field1,
  CONCAT('(',STRING_AGG(CAST(field2 AS STRING) ORDER BY id), ')') AS field2
FROM (
  SELECT 
    id, field1, field2,
    COUNTIF(field2 = 100) OVER (ORDER BY id) AS grp
  FROM yourTable
) 
GROUP BY grp
ORDER BY MIN(id) 

输出是

field1                  field2   
------                  ------   
(val1,val2)             (100,110)    
(val3,val4,val3,val3)   (100,110,130,140)    
(val1)                  (100)    

想知道这是否可能(不使用订单列)?

如果您的表中确实只有这两个字段 - 您很可能不走运,需要重新访问使用用于排序的附加字段填充此表的逻辑(作为时间线)

作为最后的手段 - 您可以尝试下面的示例,其中此类列是即时生成的 - 但请理解,绝对不能保证获得您期望的订单

#standardSQL
WITH yourTable AS (
  SELECT 'val1' AS field1, 100 AS field2 UNION ALL
  SELECT 'val2' AS field1, 110 AS field2 UNION ALL
  SELECT 'val3' AS field1, 100 AS field2 UNION ALL
  SELECT 'val4' AS field1, 110 AS field2 UNION ALL
  SELECT 'val3' AS field1, 130 AS field2 UNION ALL
  SELECT 'val3' AS field1, 140 AS field2 UNION ALL
  SELECT 'val1' AS field1, 100 AS field2 
),
tempTable AS (
  SELECT field1, field2, ROW_NUMBER() OVER() AS id  
  FROM yourTable
)
SELECT 
  CONCAT('(',STRING_AGG(field1 ORDER BY id), ')') AS field1,
  CONCAT('(',STRING_AGG(CAST(field2 AS STRING) ORDER BY id), ')') AS field2
FROM (
  SELECT 
    id, field1, field2,
    COUNTIF(field2 = 100) OVER (ORDER BY id) AS grp
  FROM tempTable
) 
GROUP BY grp
ORDER BY MIN(id) 

输出是相同的 - 但同样 - 不能保证!

field1                  field2   
------                  ------   
(val1,val2)             (100,110)    
(val3,val4,val3,val3)   (100,110,130,140)    
(val1)                  (100)    

【讨论】:

  • @raj - 您必须有一些明确的或派生的字段才能进行排序。查询引擎无法使用您的眼睛看到的视觉顺序。你的表中还有其他字段还是只有这两个?
  • 我没有用于订购的特定字段...但是是的...最后我可以从我的团队中获得一些可以用于对数据进行分组的其他字段...这解决了我的问题:)
  • 我已经对这两个答案都投了赞成票......但无法弄清楚:(选择哪一个作为接受的答案,因为两者都有帮助
  • @raj - :o) - 这真的是你的电话!
猜你喜欢
  • 1970-01-01
  • 2021-12-05
  • 1970-01-01
  • 1970-01-01
  • 2020-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多