Google bigquery BigQuery递归计算列

Google bigquery BigQuery递归计算列,google-bigquery,Google Bigquery,我需要使用表中的数据创建一个计算列。此计算列x_平均值基于计算平均值公式的应用,其中x_平均值的下一个值需要相同计算列的上一个值。我最后称之为递归计算,因为下一个值需要上一个值。该公式与以下公式有些类似: x_average = (days + (x_average * stock)) ----------------------------- (input + stock) 该表类似于以下示例: +----------------

我需要使用表中的数据创建一个计算列。此计算列x_平均值基于计算平均值公式的应用,其中x_平均值的下一个值需要相同计算列的上一个值。我最后称之为递归计算,因为下一个值需要上一个值。该公式与以下公式有些类似:

x_average =  (days + (x_average * stock)) 
            -----------------------------
                 (input + stock)
该表类似于以下示例:

+-----------------------------------+
+ date       | days | input | stock + 
+-----------------------------------+
+ 2020-01-03 | 11   |  5    |  5    +
+ 2020-01-05 | 3    |  1    |  2    +
+ 2020-01-15 | 21   |  7    |  1    +
+ 2020-01-16 | 17   |  12   |  4    +
+ 2020-01-22 | 15   |  4    |  3    +
+ (more...)
+-----------------------------------+
   
如何创建可以选择表和计算列x_average的查询

预期结果类似于:

+-----------------------------------------------+
+ date       | days | input | stock | x_average + 
+-----------------------------------------------+
+ 2020-01-03 | 11   |  5    |  5    |    1.1    +
+ 2020-01-05 | 3    |  1    |  2    |    1.733  +
+ 2020-01-15 | 21   |  7    |  1    |    2.841  +
+ 2020-01-16 | 17   |  12   |  4    |    1.772  +
+ 2020-01-22 | 15   |  4    |  3    |    2.902  +
+ (more...)
+-----------------------------------------------+
   

该表可以在1到365行之间。

下面是用于BigQuery标准SQL的,并使用BQ的脚本功能

#standardSQL
declare a, b, c array<float64>;
declare i, len int64;

/*
create temp table input_table as
  select '2020-01-03' date, 11 days, 5 input , 5 stock union all
  select '2020-01-05', 3, 1, 2 union all
  select '2020-01-15', 21, 7, 1 union all
  select '2020-01-16', 17, 12, 4 union all
  select '2020-01-22', 15, 4, 3; 
*/

set (i, len, c, a, b) = (
  select as struct 1, count(1), [1.0],
    array_agg(days / (input + stock) order by date), 
    array_agg(stock / (input + stock) order by date)
  from input_table
);

while i <= len do 
  if i = 1 then set c = [round(a[ordinal(i)], 3)]; 
    else set c = c || [a[ordinal(i)] + c[ordinal(i - 1)] * b[ordinal(i)]];
  end if;
  set i = i + 1;
end while;

create temp table output as
select * except(i), round(c[ordinal(i)], 3) as x_average
from (
  select *, row_number() over(order by date) i
  from input_table
);

select * from output order by date;
当您在表input_table上运行它时,或者您可以取消注释temp table部分以使用问题中的虚拟数据进行测试,您会得到如下结果

单击最后一行上的“查看结果”以查看结果表-输出


注意:正如我在评论中提到的,有很多方法可以实现您的逻辑,但我选择了一种使用脚本的方法。例如,你可以用JS UDF进行实验——基于上面脚本中的代码,这应该是一个简单的练习

在我看来,你忽略了什么是常见的行为,所以——投票选出有用的答案,并接受其中最好的一个!这是SO文化的重要组成部分:O请检查你以前的文章并考虑上面的问题,这将激励我们回答你的新问题。投票结束,谢谢你的几个问题:1。就行数2而言,表有多大。应该是一些额外的字段,用于定义处理行的顺序-您的表中是否有可用于此操作的行?如果不是,你必须添加它!!!1.从1到365行2。日期确定了。添加日期是有意义的,但要求它们是不同的,这样就不会有日期相同的行!也只有300行左右,这使得它有很多简单的方法。如果时间允许的话,我会看一看的,除非其他人会跳得更快:首先谢谢你的回复。我在一个脚本中通过数组和循环使用类似的方法解决了这个问题。但我想知道的是,是否有可能只使用选择来解决这个问题,而不使用WHILEs、LOOPs、array等循环。一个解决方案,其中一个或多个选择使用或不使用窗口函数,可以解决递归计算。因此,我已经提出了另一个解决方案,其中循环部分是在JS UDF中完成的,但是如果不使用脚本和JS,我如何解决它呢?可能吗?其他数据库允许“递归CTE”,这将是一个很好的解决方案,作为一个不需要脚本的独立查询,我想这是您想要的。然而,BQ并不支持这一点。@ CaytBoeNeli——如果有帮助和接受,请考虑投票。同时,为了满足您不使用脚本并使用纯基于集合的方法实现它的愿望—我认为在这种特殊情况下是可能的—但实际上,如果有相对简单的方法使用脚本或js udf,那么花时间想出棘手的解决方案的原因是什么?但是,再一次——我认为这是可行的!我的目标是看看这是否可能,解决方案是否非常复杂,这也将是一个学习SQL新技巧的机会,可以解决这个特定问题。