0

我有一些带有日期和汇总minutes计数器时间的日志。

每个小时(一行)都填写了这样一个技巧:重复记录组以填补 Google BigQuery 中的多个日期空白

问题 :

我想在仍然可用的情况下完成time专栏minutes(在此处了解,每小时最多 60 分钟)

这是所需的输出: remainingTime是由前几行产生的。假设remainingTime= 70 分钟

#standardSQL
WITH history AS (
  SELECT '2017-01-01' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-02' AS date, 'a' AS product, 100 AS minutes UNION ALL
  SELECT '2017-01-03' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-04' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-05' AS date, 'a' AS product, 30 AS minutes UNION ALL
  SELECT '2017-01-06' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-01' AS date, 'b' AS product, 100 AS minutes UNION ALL
  SELECT '2017-01-02' AS date, 'b' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-03' AS date, 'b' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-04' AS date, 'b' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-05' AS date, 'b' AS product, 0 AS minutes 

+---------+------------+---------+---------------+---------------------+
| product |    date    | minutes | remainingTime |       time          |
+---------+------------+---------+---------------------------------+
|    a    | 2017-01-01 |   0     |  10           | 60 (max 60 reached) | // 0 + 70 - 60 = 10
|    a    | 2017-01-02 |   100   |  50           | 60 (same)           | // 100 + 10 - 60 = 50
|    a    | 2017-01-03 |   0     |  0            | 50 (only 50/60)     | // 0 + 50 - 50 = 0            
|    a    | 2017-01-04 |   0     |  0            | 0 (and so on)       | // 0 + 0 - 0 = 0
|    a    | 2017-01-05 |   30    |  0            | 30                  | // 30 + 0 - 30 = 0
|    a    | 2017-01-06 |   0     |  0            | 0                   | // 0 + 0 - 0 = 0
 

... and so on for other products
+---------------+--------+------+

我几乎完成了一个复杂而丑陋的查询,但我目前遇到了一个临时计算列..

(PS:我多年没有练习 SQL,所以我在重新学习基础知识并同时发现 BigQuery 标准 SQL)

谢谢 !

4

1 回答 1

0

BigQuery 本身不支持递归操作。尝试array_agg()结合JavaScript user-defined function,但这种方法的可扩展性不是很好:

CREATE TEMP FUNCTION special_sum(x ARRAY<INT64>)
RETURNS INT64
LANGUAGE js
AS """
  var remaining = 70;
  var time = 0;
  for (const num of x)
  {
     time = Math.min(parseInt(num) + remaining, 60);
     remaining = parseInt(num) + remaining - time;
  }
  return time;
""";

WITH history AS (
  SELECT '2017-01-01' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-02' AS date, 'a' AS product, 100 AS minutes UNION ALL
  SELECT '2017-01-03' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-04' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-05' AS date, 'a' AS product, 30 AS minutes UNION ALL
  SELECT '2017-01-06' AS date, 'a' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-01' AS date, 'b' AS product, 100 AS minutes UNION ALL
  SELECT '2017-01-02' AS date, 'b' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-03' AS date, 'b' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-04' AS date, 'b' AS product, 0 AS minutes UNION ALL
  SELECT '2017-01-05' AS date, 'b' AS product, 0 AS minutes 
)
select *, 
 special_sum(array_agg(minutes) over (partition by product order by date rows unbounded preceding)) as time 
from history

在此处输入图像描述

于 2021-01-20T08:45:40.820 回答