Bigquery/标准 SQL:如何使用 sum() 聚合所有列(大约 100 列)?

Posted

技术标签:

【中文标题】Bigquery/标准 SQL:如何使用 sum() 聚合所有列(大约 100 列)?【英文标题】:Bigquery/Standard SQL: How can I aggregate all columns (about 100 columns) with sum()? 【发布时间】:2018-06-11 15:21:48 【问题描述】:

我正在寻找一种使用 sum() 函数聚合包含大约 100 列的 Bigquery 表的解决方案。但 Bigquery 标准 SQL 中不允许以下查询。

select sum(*)
from `dataset.Intermediate_Tables.eventCat_dummies`
group by Id

我想在 Bigquery 中进行这种聚合的原因是它能够处理大量数据。我尝试在 jupyter notebook 中进行相同的聚合,但每次都失败。这可能是因为数据量大(7.3 GiB csv 文件)。我试过的代码如下:

df_type = type_dummies.groupby('Id', sort=False).sum()

任何人都可以就如何获取这个大型数据集的聚合数据提供任何建议和/或替代方案?

使用示例输入和输出进行更新

输入数据

Id col1 col2 col3 col4
1  0    0    0    1
2  0    1    1    1
1  1    0    0    0
4  0    0    0    0
19 0    0    0    0
2  1    1    1    1

期望的输出

Id col1_sum col2_sum col3_sum col4_sum
1  1        0        0        1
2  1        2        2        2
4  0        0        0        0
19 0        0        0        0

在我的原始数据集中,有 100 列和 4000 万行。

【问题讨论】:

带有输入和预期输出的简化示例将帮助我们回答您的问题 @MikhailBerlyant 感谢您的评论。我会用一个简化的例子来更新它。 【参考方案1】:

以下是 BigQuery StandardSQL 的示例

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 1 id, 1 a, 2 b, 3 c UNION ALL
  SELECT 1, 4, 5, 6 UNION ALL
  SELECT 2, 7, 8, 9
)
SELECT id, 
  SUM((
    SELECT SUM(CAST(SPLIT(pair, ':')[SAFE_OFFSET(1)] AS INT64)) 
    FROM UNNEST(SPLIT(REGEXP_REPLACE(TO_JSON_STRING(t), r'[]', ''))) pair 
    WHERE SPLIT(pair, ':')[SAFE_OFFSET(0)] != '"id"'
  )) val
FROM `project.dataset.table` t
GROUP BY id    

结果为

Row id  val  
1   1   21   
2   2   24     

如您所见 - 以上不依赖于列数 此外,它假设除id 列之外的所有列都需要求和。如果您要排除更多列 - 您可以分别调整 WHERE 子句

根据提供的详细信息进行更新 所以你想对每一列求和(最初我读你的问题,好像你想通过 id 将所有列的值加在一起)

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 1 id, 1 a, 2 b, 3 c UNION ALL
  SELECT 1, 4, 5, 6 UNION ALL
  SELECT 2, 7, 8, 9
)
SELECT id, 
  REPLACE(SPLIT(pair, ':')[SAFE_OFFSET(0)], '"', '')  col,
  SUM(CAST(SPLIT(pair, ':')[SAFE_OFFSET(1)] AS INT64)) val
FROM (
  SELECT id, 
    ARRAY(
      SELECT pair
      FROM UNNEST(SPLIT(REGEXP_REPLACE(TO_JSON_STRING(t1), r'[]', ''))) pair 
      WHERE SPLIT(pair, ':')[SAFE_OFFSET(0)] != '"id"'
    ) arr
  FROM `project.dataset.table` t1
) t2,
UNNEST(arr) pair
GROUP BY id, col
ORDER BY id, col

这会给你下面的结果

Row id  col val  
1   1   a   5    
2   1   b   7    
3   1   c   9    
4   2   a   7    
5   2   b   8    
6   2   c   9    

这个结果是你需要的扁平化版本,在大多数实际用例中比旋转的更有效

不过,如果您想转换此结果 - 请参阅 https://***.com/a/35808045/5221944

【讨论】:

嗨,米哈伊尔,感谢您的帮助。我正在尝试了解您的解决方案。然后我想到了几个问题。第一个问题是:当您在解决方案中使用 WITHUNNEST 子句时,是否隐含涉及列名?第二个问题是 21 是如何计算的?如果我的问题太天真,我希望你不会介意。顺便说一句,我用示例输入和所需输出更新了问题。你能告诉我这个解决方案是否仍然有效吗?再次感谢。 查看答案更新。同时 - 1) WITH 仅用于模拟您的数据 - 您可以删除该部分并使用您自己的 project.dataset.table 它适用于您的表和 UNNEST 中的尽可能多的列 - 正如您从脚本/查询中看到的那样- 根本不使用列名! 2) 21 是 id=1 (1+2+3+4+5+6=21) 的所有列的总和-当然这是我最初理解您的问题的方式-但是在您提供了更多详细信息之后-很清楚那不是您想要的-所以我在最初的答案中添加了更新。希望这会有所帮助:o) 感谢您分享宝贵的知识,米哈伊尔。您的解决方案和解释方法对我来说看起来很棒。我可以从中学到很多东西。尽管我没有尝试将您的想法应用于我的数据集,但我喜欢您的解决方案,并且相信它会引导我到正确的地方。我会投赞成票,希望它能帮助更多遇到类似问题的人。

以上是关于Bigquery/标准 SQL:如何使用 sum() 聚合所有列(大约 100 列)?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用标准 SQL 在 BigQuery 中透视表?

BigQuery 标准 SQL 如何将行转换为列

如何使用标准 SQL (BigQuery) 与几个月不同

如何使用 Java API 使用标准 SQL 创建 BigQuery 视图?

BigQuery:如何在 C# 中启用标准 SQL

如何在 BigQuery 标准 SQL 中查询 Bigtable 列值?