BigQuery 中的递归计算

Recursive calculation in BigQuery

我需要将库存计算为动态和递归值,作为简单的等式:

n值指的是一个周期时间(月、日、年等)

总是当股票价值为负时,用零代替。

如何在 Big Query 中进行计算?这是一个例子:

WITH `project.dataset.table` AS (
  SELECT 10 entrada, 5  venda, 8 quebra, 8 mes, 2019 ano UNION ALL
  SELECT 12, 8 , 3, 9, 2019  UNION ALL
  SELECT 20, 15, 2, 10, 2019  UNION ALL
  SELECT 30, 12, 2, 11, 2019  UNION ALL
  SELECT 20, 10, 5, 12, 2019  UNION ALL
  SELECT 30, 12, 2, 1, 2020  UNION ALL
  SELECT 30, 12, 2, 2, 2020  UNION ALL
  SELECT 30, 12, 2, 3, 2020  
)

SELECT entrada, venda, quebra,
  variacao,
  greatest(coalesce(lag(variacao) over (partition by 'project.dataset.table' order by ano, mes),0) + entrada - venda - quebra, 0) as estoque

FROM (
  SELECT *, 
    entrada - venda - quebra AS variacao
  FROM `project.dataset.table`
)

预期结果为:

entrada venda   quebra  variacao    estoque
10  5   8   -3  0
12  8   3   1   1
20  15  2   3   4
30  12  2   16  20
20  10  5   5   25
30  12  2   16  41
30  12  2   16  57
30  12  2   16  73

但是,上面代码的结果是:

entrada venda   quebra  variacao    estoque
10  5   8   -3  0
12  8   3   1   0
20  15  2   3   4
30  12  2   16  19
20  10  5   5   21
30  12  2   16  21
30  12  2   16  32
30  12  2   16  32

提前致谢!

使用所有股票价值的“内部”总和解决。使用这个:

   WITH `project.dataset.table` AS (
  SELECT 10 entrada, 5  venda, 8 quebra, 8 mes, 2019 ano UNION ALL
  SELECT 12, 8 , 3, 9, 2019  UNION ALL
  SELECT 20, 15, 2, 10, 2019  UNION ALL
  SELECT 30, 12, 2, 11, 2019  UNION ALL
  SELECT 20, 10, 5, 12, 2019  UNION ALL
  SELECT 30, 12, 2, 1, 2020  UNION ALL
  SELECT 30, 12, 2, 2, 2020  UNION ALL
  SELECT 30, 12, 2, 3, 2020  
)

SELECT entrada, venda, quebra,
  sum(greatest(entrada - venda - quebra,0)) over (partition by 'project.dataset.table' order by ano, mes) as estoque,
  mes, ano
  FROM `project.dataset.table`

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

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

WITH `project.dataset.table` AS (
  SELECT 10 entrada, 5  venda, 8 quebra, 8 mes, 2019 ano UNION ALL
  SELECT 12, 8 , 3, 9, 2019  UNION ALL
  SELECT 20, 15, 2, 10, 2019  UNION ALL
  SELECT 30, 12, 2, 11, 2019  UNION ALL
  SELECT 20, 10, 5, 12, 2019  UNION ALL
  SELECT 30, 12, 2, 1, 2020  UNION ALL
  SELECT 30, 12, 2, 2, 2020  UNION ALL
  SELECT 30, 12, 2, 3, 2020  
)
select *, 
 special_sum(array_agg(entrada - venda - quebra) over (order by ano, mes rows unbounded preceding)) as estoque
from `project.dataset.table`