在 Google BigQuery 中进行聚合时是不是可以运行计算
Posted
技术标签:
【中文标题】在 Google BigQuery 中进行聚合时是不是可以运行计算【英文标题】:Is it possible to run calculations while aggregating in Google BigQuery在 Google BigQuery 中进行聚合时是否可以运行计算 【发布时间】:2019-06-29 13:02:28 【问题描述】:在 StandardSQL 中,是否可以在分组过程中对每一行运行操作?我不确定我是否问对了问题。这是一个例子。
假设我有 3 行这样的:
| move_id | item_id | quantity | value |
|---------|---------|----------|-------|
| 1 | 1 | 10 | 100 |
| 1 | 2 | 20 | 150 |
| 1 | 3 | 30 | 200 |
我现在想按 move_id 对表格进行分组,根据每行数量与最小数量的比例求和。
例如最小数量是 10,第 2 行的数量是 20,这意味着它的值应该在求和之前减半。第 3 行的数量为 30,这意味着它的值应该在求和之前减少到三分之一。
所以我的最终值列应该是 100 + (150 / 2) + (200 / 3) = 241.67。
我的结果应该是:
| move_id | quantity | value |
|---------|----------|--------|
| 1 | 10 | 241.67 |
查询应该是这样的:
SELECT ANY_VALUE(move_id) AS move_id, MIN(quantity) AS quantity, SUM([THIS IS MY QUESTION, WHAT GOES HERE?]) as value FROM table GROUP BY move_id;
这可能吗?
【问题讨论】:
【参考方案1】:以下是 BigQuery 标准 SQL 并且一次性完成所有操作
#standardSQL
SELECT move_id,
MIN(quantity) AS quantity,
SUM(value/quantity) * MIN(quantity) AS value
FROM `project.dataset.table`
GROUP BY move_id
如果适用于您问题的样本数据 - 结果是
Row move_id quantity value
1 1 10 241.66666666666669
正如您在此处看到的 - 您可以转换公式,而不是在查询中拆分计算/聚合,如下所示
100 + (150 / 2) + (200 / 3)
(100 * 10 / 10 + (150 * 10 / 20) + (200 * 10 / 30)
((100 / 10 + (150 / 20) + (200 / 30)) * 10
SUM(值/数量)* MIN(数量)
所以,你最终只是“一次性”完成了简单的聚合
【讨论】:
这真是太棒了。谢谢! 哈哈。同意。那么你可能想接受这个答案吗? 我觉得回答我问题的第一个答案应该仍然被接受。你的并没有让另一个更不正确。不确定这方面的正确礼仪,你可能比我更清楚。不过我确实给了你一个赞成票! 使用这个方法,有没有什么办法可以保证MIN(quantity) > 0,如果不是,设置value = 0?我试过这样的 case 语句或 IF 函数:IF(MIN(quantity) > 0, SUM(value / quantity) * MIN(quantity), 0)
,但它似乎不起作用。我仍然得到 0 错误除法。
我也试过IF(COUNTIF(quantity = 0) > 0, 0, SUM(value / quantity) * MIN(quantity))
,但这似乎也不起作用。除以 0 错误。【参考方案2】:
查询中有些困难的部分是您想要聚合,但您想到的总和本身需要聚合的结果 - 每个 move_id
组的最小值 quantity
。这里的一个选项是首先在 CTE 中生成最小 quantity
,然后使用您的逻辑聚合该 CTE。
WITH cte AS (
SELECT *, MIN(quantity) OVER (PARTITION BY move_id) min_quantity
FROM yourTable
)
SELECT
move_id,
MIN(quantity) AS quantity,
SUM(value * min_quantity / quantity) AS value
FROM cte
GROUP BY
move_id;
Demo
注意:上面的演示使用 SQL Server,但使用的 SQL 是 ANSI 兼容的,并且应该也可以在 BigQuery 上运行,没有任何问题。
另外,如果您的 BigQuery 版本不支持 cte,那么您可以将 CTE 中包含的代码作为子查询内联。
【讨论】:
谢谢,我试试看。你有没有机会试着用文字来解释你在做什么?我一直在查看OVER
子句作为一种方法来做到这一点,但无法弄清楚。查询在做什么?
@flyingL123 我在答案中添加了解释。我发布的只是这样做的一种方式。【参考方案3】:
在没有 CTE 的情况下,您可以使用 Derived Table(子查询)分别获取每个 move_id
的最小数量。然后在主查询中使用它们来计算总和:
SELECT t.move_id,
dt.min_quantity,
Sum(t.value / ( t.quantity / dt.min_quantity )) AS value
FROM your_table AS t
JOIN (SELECT move_id,
Min(quantity) AS min_quantity
FROM your_table
GROUP BY move_id) AS dt
ON dt.move_id = t.move_id
GROUP BY t.move_id
SQL Fiddle Demo
【讨论】:
BigQuery 的最新版本do support common table expressions。以上是关于在 Google BigQuery 中进行聚合时是不是可以运行计算的主要内容,如果未能解决你的问题,请参考以下文章
Mongoose 在使用 $facet 进行聚合时如何使用 populate()?
SQL (Hive):在使用 GROUP BY 进行聚合时使用窗口函数