Google BigQuery 选择记录中所有嵌套字段的总和

Posted

技术标签:

【中文标题】Google BigQuery 选择记录中所有嵌套字段的总和【英文标题】:Google BigQuery select sum of all the nested fields in a record 【发布时间】:2017-12-12 12:23:05 【问题描述】:

我的架构类似于下面

|- name
+- cars
|  |- tesla integer
|  |- ferrari integer

假设每条记录指定一个汽车订单,每个订单指定订购的不同汽车的数量。

现在我想查询该表以获得所有不同汽车类型的总和。 所以我想要SELECT SUM(cars.*) from table_name 之类的东西,因为我不知道汽车可能有哪些所有可能的嵌套字段。

每次添加新车型时都会动态生成架构,因此在我的查询中我不可能指定所有字段名称,因为我不会拥有它们。

示例数据 -

name    | cars.tesla | cars.ferrari
vendor1 |     12     |      10
vendor1 |     5      |      5
vendor2 |     4      |      3   

vendor1 的期望输出 -

name    | total_tesla | total_ferrari 
vendor1 |     17      |     15

所以,我想选择嵌套在特定记录下的所有字段的总和。有什么办法可以做到吗?

【问题讨论】:

【参考方案1】:

以下是 BigQuery 标准 SQL

#standardSQL
SELECT name, SUM(SAFE_CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64)) total
FROM `project.dataset.table` t,
UNNEST(SPLIT(REGEXP_REPLACE(JSON_EXTRACT(TO_JSON_STRING(t), '$.cars'), r'^|$', ''))) kv
GROUP BY name

您可以使用下面的虚拟数据测试/玩上面的内容

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'a' name, STRUCT<tesla INT64, ferrari INT64>(1, 2) cars UNION ALL
  SELECT 'b', STRUCT(3,4)
)
SELECT name, SUM(SAFE_CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64)) total
FROM `project.dataset.table` t,
UNNEST(SPLIT(REGEXP_REPLACE(JSON_EXTRACT(TO_JSON_STRING(t), '$.cars'), r'^|$', ''))) kv
GROUP BY name

结果是

name    total    
a       3    
b       7    

下面是上面的简化/重构版本:

#standardSQL
SELECT name, 
  (
    SELECT SUM(SAFE_CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64)) 
    FROM UNNEST(SPLIT(REGEXP_REPLACE(TO_JSON_STRING(cars), r'^|$', ''))) kv
  ) total
FROM `project.dataset.table`

最后是“最终”版本:

#standardSQL
CREATE TEMP FUNCTION SUM_NESTED(root STRING) AS (
  (SELECT SUM(SAFE_CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64)) 
  FROM UNNEST(SPLIT(REGEXP_REPLACE(root, r'^|$', ''))) kv)
);

SELECT name, SUM_NESTED(TO_JSON_STRING(cars)) total
FROM `project.dataset.table`  

更新以解决已编辑的问题

下面应该给你方向 - 它会给你扁平化的结果 (you should search this site then for how to pivot it - there are plenty of questions/answers on that topic here)

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'vendor1' name, STRUCT<tesla INT64, ferrari INT64>(12, 10) cars UNION ALL
  SELECT 'vendor1', STRUCT(5, 5) UNION ALL
  SELECT 'vendor2', STRUCT(4,3) UNION ALL
  SELECT 'vendor2', STRUCT(1,NULL)
)
SELECT 
  name, 
  REPLACE(SPLIT(kv, ':')[OFFSET(0)], '"', '') car, 
  SUM(SAFE_CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64)) total
FROM `project.dataset.table`,
UNNEST(SPLIT(REGEXP_REPLACE(TO_JSON_STRING(cars), r'^|$', ''))) kv
GROUP BY name, car
-- ORDER BY name, car  

结果是

name        car         total    
vendor1     ferrari     15   
vendor1     tesla       17   
vendor2     ferrari     3    
vendor2     tesla       5    

【讨论】:

我正在尝试运行它,但是我在列中的 null 值有问题,它无法转换它们。 尝试 SAFE_CAST 而不是 CAST 并让我们知道结果。我用 SAFE_CAST 调整了答案 它与SAFE_CAST 合作。但没有给出我期望的结果,而是将所有汽车(不是单个汽车类型的总和)总结为一个名称,而是我想要所有汽车类型的单独总和。 更新您的问题,以便清楚您期望的确切结果(输入和输出示例在许多情况下都有帮助)。此外,即使您说这不是您所期望的 - 但这正是您在原始问题中所说的。因此,如果您只是改变主意-我建议您提出新问题:o) 对于问题不够清晰,我深表歉意,我已对其进行了编辑并添加了所需的输出。我的期望从一开始就一样

以上是关于Google BigQuery 选择记录中所有嵌套字段的总和的主要内容,如果未能解决你的问题,请参考以下文章

Google Bigquery 查询记录数据 - 专利

在 Bigquery 中有效地取消嵌套值? (选择/案例/其他?)

BigQuery:从多个嵌套列中选择 * 替换

无法使用 google bigquery(标准)取消嵌套某些字段

如何从基于嵌套 json 的 BigQuery 表中进行选择?

Google BigQuery - 更新嵌套的重复字段