在 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 中进行聚合时是不是可以运行计算的主要内容,如果未能解决你的问题,请参考以下文章

进行聚合时如何忽略数据框中的特定列

在 SQLite 中计算多个聚合时可以消除子查询吗?

Mongoose 在使用 $facet 进行聚合时如何使用 populate()?

SQL (Hive):在使用 GROUP BY 进行聚合时使用窗口函数

当域事件影响同一有界上下文中的多个聚合时,EventSourcing中的StreamId是什么?

在clickhouse中与max()聚合时如何连续选择相应的值?