【问题标题】:BigQuery - How to create a new column where the calculation includes the new column itself?BigQuery - 如何创建一个新列,其中计算包括新列本身?
【发布时间】:2016-12-02 06:53:23
【问题描述】:

---总结---

我有三列:[visitorID]、[rank]、[numbers]。

在 BigQuery 中, 我想创建一个新列[计算], 这是 [数字] 和 [计算] 本身总和的一部分,包括指定条件。

我现在遇到的问题是“在 BigQuery 中,我无法创建需要计算的列,包括我正在创建的列”。 我不确定我的概念或想法是否合适, 也希望有更好的建议。

---详情---

*我的桌子:

一个包含三列的表:[visitorID]、[rank]、[numbers]。

*我需要创建的新列:

需要创建列[计算]。

*计算的定义:

按 [visitorID] 和 [rank] 排序后, [计算] 是

(i) 如果 [数字] = 0,那么 [计算] = 0 (ii) 如果 [numbers] 0,则将当前 [numbers] 值与之前的 [calculation] 数相加。 (iii) 基于(ii),如果总和大于30,则[计算] = 0,ELSE [计算]保持相同的总和值。

请参见下面的示例。

*我遇到的问题

我需要使用 BigQuery 来进行这种计算。 但是,我想出的是“窗口求和函数”,这似乎不是一个很好的解决方案。 我认为关键是“在 BigQuery 中,我无法创建需要计算的列,包括我正在创建的列”。

请参见下面的示例。

也就是说,我总是需要现有的值来创建一个新列。 我的示例查询如下,无法解决问题。 您还可以查看打印屏幕以了解问题所在。

请参阅下面的示例查询。

SELECT 
  visitorID, 
  rank, 
  numbers, 
  SUM(numbers) OVER (PARTITION BY visitorID ORDER BY rank) AS window_sum_current, 
  SUM(numbers) OVER (PARTITION BY visitorID ORDER BY rank ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS window_sum_prec1     
FROM sample_table

*寻求建议

我想征求意见。 (1) 在 BigQuery 中,这个问题是否可以解决? (2)我缺乏什么方法或概念? (3) 解决 BigQuery 问题的更好方法是什么?

非常感谢。

【问题讨论】:

    标签: mysql sql sql-server google-bigquery


    【解决方案1】:

    对于 BigQuery,到目前为止我可以提出的唯一解决方案如下
    它产生的结果正是您期望的价格,让您了解BigQuery User-Defined Functions。如果使用得当,功能非常强大。在某些情况下,它存在内存问题,很快就会根据this link 解决。
    我强烈建议采用此功能!

    SELECT visitorID, rank, numbers, calculation FROM JS(
    // input table
    ( SELECT visitorID, 
        GROUP_CONCAT(CONCAT(STRING(100000 + rank), ',', STRING(numbers)), ';') AS list
      FROM
        (SELECT 1001 AS visitorID, 1 AS rank, 0 AS numbers), 
        (SELECT 1001 AS visitorID, 2 AS rank, 13 AS numbers), 
        (SELECT 1001 AS visitorID, 3 AS rank, 13 AS numbers), 
        (SELECT 1001 AS visitorID, 4 AS rank, 6 AS numbers), 
        (SELECT 1001 AS visitorID, 5 AS rank, 4 AS numbers), 
        (SELECT 1001 AS visitorID, 6 AS rank, 5 AS numbers), 
        (SELECT 1001 AS visitorID, 7 AS rank, 26 AS numbers), 
        (SELECT 1001 AS visitorID, 8 AS rank, 32 AS numbers), 
        (SELECT 999 AS visitorID, 1 AS rank, 0 AS numbers), 
        (SELECT 999 AS visitorID, 2 AS rank, 2 AS numbers), 
        (SELECT 999 AS visitorID, 3 AS rank, 2 AS numbers), 
        (SELECT 999 AS visitorID, 4 AS rank, 2 AS numbers), 
        (SELECT 999 AS visitorID, 5 AS rank, 2 AS numbers), 
        (SELECT 999 AS visitorID, 6 AS rank, 24 AS numbers) 
      GROUP BY visitorID
    ),
    // input columns
    visitorID, list,
    // output schema
    "[{name: 'visitorID', type: 'integer'},
    {name: 'rank', type: 'integer'},
    {name: 'numbers', type: 'integer'},
    {name: 'calculation', type: 'integer'}]",
    // function
    "function(r, emit){
      var list = r.list.split(';');
      list.sort();
      calculation = 0;
      for (var i = 0; i < list.length; i++) {
        rank = parseInt(list[i].split(',')[0]) - 100000;
        numbers = parseInt(list[i].split(',')[1]);
        if (numbers !== 0) calculation += numbers;
        if (calculation > 30) calculation = 0;
        emit({visitorID: r.visitorID, rank: rank, 
              numbers: numbers, calculation: calculation});
      }
     }"
    )
    

    【讨论】:

    • 嗨,米哈伊尔,我正在尝试您的方法,这是令人难以置信的成功。太感谢了。我发现有一个链接storage.googleapis.com/bigquery-udf-test-tool/testtool.html 可以测试UDF(但仍然找不到调试器......很难调试UDF)。尽管如此,还是非常感谢您的帮助。我仍然理解您使用的逻辑(特别是为什么使用 GROUP_COONCAT),并且我发现不使用 GROUP_CONCAT,for-loop 部分的长度将是一个问题。刚刚学到了很棒的一课:-)
    【解决方案2】:

    您尝试执行的操作在 SQL Select 语句中是不可能的。您要求做一些本来就需要变量、循环和 if 语句的事情,这些在 SQL Select 语句中都不可用。

    当然,您可以使用表值函数和存储过程在 SQL 代码中执行此类操作。使用专为您想要执行的操作而构建的外部编程语言可能是最简单的方法。

    在 SQL 中对 [visitorID]、[rank]、[numbers] 运行查询,然后在输出到所需的任何文件或屏幕时开发 [calculation] 数据。

    希望它能澄清你的情况。

    【讨论】:

      猜你喜欢
      • 2018-08-13
      • 1970-01-01
      • 2015-05-20
      • 1970-01-01
      • 2019-10-01
      • 1970-01-01
      • 2015-10-02
      • 2021-12-26
      • 2017-10-23
      相关资源
      最近更新 更多