如何查询非规范化 BigQuery 表以输出嵌套和重复的字段
Posted
技术标签:
【中文标题】如何查询非规范化 BigQuery 表以输出嵌套和重复的字段【英文标题】:How to query a denormalized BigQuery table to output nested and repeated fields 【发布时间】:2019-05-10 02:42:20 【问题描述】:我有一些数据定期加载到 BigQuery 数据库中。每一行代表作为履行订单的一部分的一件库存的移动。
相关订单和“order_product”信息作为嵌套记录嵌入在行中。
以下是一些行的示例:
|----------|----------|----------|------------------|------------------------|---------------------|---------------------------------|
| move_id | quantity | order.id | order_product.id | order_product.quantity | order_product.price | item_reference_number |
|----------|----------|----------|------------------|------------------------|---------------------|---------------------------------|
| 1 | 1 | 1 | 1 | 1 | 5 | ABC |
|----------|----------|----------|------------------|------------------------|---------------------|---------------------------------|
| 2 | 1 | 1 | 2 | 1 | 7 | DEF |
|----------|----------|----------|------------------|------------------------|---------------------|---------------------------------|
| 3 | 1 | 1 | 2 | 1 | 7 | XYZ |
|----------|----------|----------|------------------|------------------------|---------------------|---------------------------------|
如您所见,该表显示了三个股票走势。都与订单 1 相关。
Order 1 由一个 order_product 1 和一个 order_product 2 组成。Order_product 1 由一个库存移动组成,move_id 1 用于项目 ABC。
Order_product 2 包含两个库存变动,move_id 2 用于商品 DEF,move_id 3 用于商品 XYZ。
如何编写查询以将此数据转换为具有适当嵌套/重复字段的表?换句话说,我希望数据看起来像这样:
|-----------|------------------|------------------------|---------------------|------------------------|---------------------|----------------------------------|
| order_id | order_product.id | order_product.quantity | order_product.price | stock_move.id | stock_move.quantity | stock_move.item_reference_number |
|-----------|------------------|------------------------|---------------------|------------------------|---------------------|----------------------------------|
| 1 | 1 | 1 | 5 | 1 | 1 | ABC |
| |------------------|------------------------|---------------------|------------------------|---------------------|----------------------------------|
| | 2 | 1 | 7 | 2 | 1 | DEF |
| | | | |------------------------|---------------------|----------------------------------|
| | | | | 3 | 1 | XYZ |
|-----------|------------------|------------------------|---------------------|------------------------|---------------------|----------------------------------|
我一直在阅读this post,这似乎表明ARRAY_AGG
可能是我需要的,但我不知道如何正确使用它来解决我的问题。
我认为我的问题是我正在努力将嵌套的 order_products 减少到每一行,同时为每个 order_product 填充正确的嵌套/重复库存移动。
甚至可以按照我的要求做吗?我非常感谢任何帮助我指出正确的方向。
【问题讨论】:
【参考方案1】:以下是 BigQuery 标准 SQL
#standardSQL
SELECT order_id,
ARRAY_AGG(product ORDER BY product.id) order_product,
ARRAY_CONCAT_AGG(stock_move) stock_move
FROM (
SELECT order_id,
STRUCT(order_product.id, order_product.quantity, order_product.price) product,
ARRAY_AGG(STRUCT(move_id AS id, quantity AS quantity, item_reference_number AS item_reference_number)) stock_move
FROM `project.dataset.table`
GROUP BY order_id, order_product.id, order_product.quantity, order_product.price
ORDER BY order_product.id -- <-- this is to make sure stock_move array is ordered as in your expected output - but really not needed here
)
GROUP BY order_id
当应用于您的示例数据时 - 上面会产生如下结果
我不确定这是否正是你的意思,因为你的例子仍然有点模棱两可,但希望这能给你一个想法
另外请注意:我假设您的示例中的 order.id
实际上是 order_id
否则它没有多大意义,但我可能对此有误(正如我提到的那样,您的示例仍然“有点”模棱两可)
【讨论】:
感谢您的回复。它应该是order.id
。订单是行的嵌套资源。实际上,我想保留订单上的其他字段,例如order.source
,但为了简化示例,我没有显示它们。这有什么改变吗?另外,有什么方法可以解释查询的不同部分正在做什么?我是新手,想了解每件作品的原因。
您说ORDER BY order_product.id
实际上没有必要是什么意思?我发现没有它,库存变动与正确的订单产品无关,但我很困惑为什么会这样。我认为我缺少有关嵌套字段的一些基本知识。这些库存变动不是嵌套在他们的 order_product 行中吗?那么他们不应该自动留在 order_product 行的任何地方吗?
刮掉这个额外的评论 - 我应该在发布答案时删除这个。显然没有命令它不会产生预期的结果,这就是我在那里拥有它的原因
感谢您的回复。但这对我来说并不明显。为什么需要 ORDER BY?那些库存移动行不是嵌套在它们的父 order_products 中吗?此外,外部查询 ARRAY_AGG 函数中是否需要 ORDER BY ?那个好像没什么区别。
正如我所提到的-您问题中的示例模棱两可,尚不清楚您的期望。所以我试图尽可能接近你的预期结果(甚至是视觉上)所以这就是为什么我添加了 order 以便它按产品顺序输出【参考方案2】:
以下 SQL 会满足您的期望吗?
我以 order_product 方式创建了 stock_move。
WITH original_table AS (
SELECT 1 AS move_id, 1 AS quantity, STRUCT(1 AS id) AS `order`, STRUCT(1 AS id, 1 AS quantity, 5 AS price) AS order_product, "ABC" AS item_reference_number
UNION ALL
SELECT 2 AS move_id, 1 AS quantity, STRUCT(1 AS id) AS `order`, STRUCT(2 AS id, 1 AS quantity, 7 AS price) AS order_product, "DEF" AS item_reference_number
UNION ALL
SELECT 3 AS move_id, 1 AS quantity, STRUCT(1 AS id) AS `order`, STRUCT(2 AS id, 1 AS quantity, 7 AS price) AS order_product, "XYZ" AS item_reference_number
),
t1 AS (
SELECT DISTINCT
move_id,
quantity,
`order`.id AS order_id,
order_product.id AS order_product_id,
order_product.quantity AS order_product_quantity,
order_product.price AS order_product_price,
item_reference_number
FROM original_table
),
t2 AS (
SELECT
order_id,
order_product_id,
order_product_quantity,
order_product_price,
ARRAY_AGG(STRUCT(move_id, quantity, item_reference_number) ORDER BY move_id) AS stock_move
FROM t1
GROUP BY order_id, order_product_id, order_product_quantity, order_product_price
),
t3 AS (
SELECT
order_id,
ARRAY_AGG(STRUCT(order_product_id AS id, order_product_quantity AS quantity, order_product_price AS price, stock_move) ORDER BY order_product_id) AS order_product
FROM t2
GROUP BY order_id
)
SELECT * FROM t3
|-----------|------------------|------------------------|---------------------|----------------------------------|-----------------------------------|------------------------------------------------|
| order_id | order_product.id | order_product.quantity | order_product.price | order_product.stock_move.move_id | order_product.stock_move.quantity | order_product.stock_move.item_reference_number |
|-----------|------------------|------------------------|---------------------|----------------------------------|-----------------------------------|------------------------------------------------|
| 1 | 1 | 1 | 5 | 1 | 1 | ABC |
| |------------------|------------------------|---------------------|----------------------------------|-----------------------------------|------------------------------------------------|
| | 2 | 1 | 7 | 2 | 1 | DEF |
| | | | |----------------------------------|-----------------------------------|------------------------------------------------|
| | | | | 3 | 1 | XYZ |
|-----------|------------------|------------------------|---------------------|----------------------------------|-----------------------------------|------------------------------------------------|
【讨论】:
以上是关于如何查询非规范化 BigQuery 表以输出嵌套和重复的字段的主要内容,如果未能解决你的问题,请参考以下文章
BigQuery 嵌套表 UPDATE 基于非嵌套数据和嵌套数据的条件
格式化 TABLE_DATE_RANGE() BigQuery 的时间戳输出
如何从 Bigquery 中的这个嵌套 JSON 类型列中查询特定的内容