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 选择记录中所有嵌套字段的总和的主要内容,如果未能解决你的问题,请参考以下文章
在 Bigquery 中有效地取消嵌套值? (选择/案例/其他?)
无法使用 google bigquery(标准)取消嵌套某些字段