【问题标题】:BigQuery JavaScript UDF to merge lists/arrays of values用于合并值列表/数组的 BigQuery JavaScript UDF
【发布时间】:2020-01-16 01:52:53
【问题描述】:

所以我有这些列,col1colx 都是 STRING/TEXT 类型:

id   |   col1   |    col2   | col3     | ...
-----|----------|-----------|----------|------
1    |[{"a":1}] | [{"b":2}] | [{"c":3}]| ...
-----|----------|-----------|----------|------
2    | ....

有没有一种简单的方法可以使用 UDF 连接和合并这些值,结果是 [{"a":1}, {"b":2}, {"c":3}]?

我考虑过先进行字符串连接和正则表达式替换,但是 SQL 会很冗长,所以我现在正在研究 JS UDF。但是,我不知道如何使用任意数量的列/参数来做到这一点。感谢您的想法!

编辑 1

澄清一下,对于 UDF 实现,如果我可以按任意顺序选择任意数量的 args 将是理想的,即

  • func(col1, col2) 给了我[{"a":1}, {"b":2}],然后
  • func(col1, col2, col3) 给我[{"a":1}, {"b":2}, {"c": 3}]

【问题讨论】:

    标签: javascript google-bigquery user-defined-functions


    【解决方案1】:

    是否可以使 args 具有选择性,例如,我可以选择 combine(col1, col2) 或 combine(col1, col2, col100)?

    func(col1, col2) 给我 [{"a":1}, {"b":2}] 和
    func(col1, col2, col3) 给我 [{"a":1}, {"b":2}, {"c": 3}]。

    以下示例适用于 BigQuery 标准 SQL

    #standardSQL
    CREATE TEMP FUNCTION combine(s ANY TYPE) AS (
      REGEXP_REPLACE(TO_JSON_STRING(s), r'\\"', '"')
    );
    WITH `project.dataset.table` AS (
      SELECT 1 id, '{"a":1}' col1, '{"b":2}' col2, '{"c":3}' col3 UNION ALL
      SELECT 2 id, '{"d":4}' col1, '{"e":5}' col2, '{"f":6}' col3 
    )
    SELECT id, 
      combine([col1, col2]) combined_2columns,
      combine([col1, col2, col3]) combined_3columns
    FROM `project.dataset.table` t
    -- ORDER BY id  
    

    有输出

    Row id  combined_2columns       combined_3columns    
    1   1   ["{"a":1}","{"b":2}"]   ["{"a":1}","{"b":2}","{"c":3}"]  
    2   2   ["{"d":4}","{"e":5}"]   ["{"d":4}","{"e":5}","{"f":6}"] 
    

    【讨论】:

    • 很好,在这种情况下,参数是相同的类型:列数组——我期待一个与 CONCAT 类似的参数列表。很好的答案,只要它有效!
    • 再看一遍,这并不能完全解决问题,因为原始列包含“括号”——它们是 json arrays 的格式。
    • 只需应用一点额外的格式。非常简单!答案为您提供核心 - 然后做任何您需要的额外工作
    【解决方案2】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    CREATE TEMP FUNCTION combine(s ANY TYPE) AS ((
      SELECT STRING_AGG(x ORDER BY OFFSET)
      FROM UNNEST(SPLIT(REGEXP_REPLACE(FORMAT('%t', s), r'\)$', ''))) x WITH OFFSET
      WHERE OFFSET > 0
    ));
    SELECT id, combine(t) AS combined_columns
    FROM `project.dataset.table` t
    ORDER BY id  
    

    您可以使用虚拟数据进行测试,如下例所示

    #standardSQL
    CREATE TEMP FUNCTION combine(s ANY TYPE) AS ((
      SELECT STRING_AGG(x ORDER BY OFFSET)
      FROM UNNEST(SPLIT(REGEXP_REPLACE(FORMAT('%t', s), r'\)$', ''))) x WITH OFFSET
      WHERE OFFSET > 0
    ));
    WITH `project.dataset.table` AS (
      SELECT 1 id, '{"a":1}' col1, '{"b":2}' col2, '{"c":3}' col3 UNION ALL
      SELECT 2 id, '{"d":4}' col1, '{"e":5}' col2, '{"f":6}' col3 
    )
    SELECT id, combine(t) AS combined_columns
    FROM `project.dataset.table` t
    ORDER BY id  
    

    结果

    Row id  combined_columns     
    1   1   {"a":1}, {"b":2}, {"c":3}    
    2   2   {"d":4}, {"e":5}, {"f":6}    
    

    如果您希望组合值是数组 - 将 STRING_AGG() 替换为 ARRAY_AGG() 并且结果将为

    Row id  combined_columns     
    1   1   {"a":1}  
            {"b":2}  
            {"c":3}  
    2   2   {"d":4}  
            {"e":5}  
            {"f":6}  
    

    显然,只要第一列是idcol1 thru colx are all of type STRING,如上所述,上述内容适用于任意数量的列。否则,以上需要稍作调整 - 但这些将是非常小的变化......

    【讨论】:

    • 太棒了,谢谢!是否可以使参数具有选择性,例如,我可以选择combine(col1, col2)combine(col1, col2, col100)
    • 这是可能的,但需要不同的实现。您的问题是专门要求合并所有列。发布包含所有新细节的新问题,我(或其他人)会回答。同时,如果您看到此答案对您有帮助,请投票并接受
    • 为含糊不清道歉,我不清楚I'm lost at how to do it with arbitrary number of columns/args。澄清了问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-09
    • 1970-01-01
    • 2021-09-27
    相关资源
    最近更新 更多