用于合并值列表/数组的 BigQuery JavaScript UDF

Posted

技术标签:

【中文标题】用于合并值列表/数组的 BigQuery JavaScript UDF【英文标题】:BigQuery JavaScript UDF to merge lists/arrays of values 【发布时间】: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]

【问题讨论】:

【参考方案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。澄清了问题。

以上是关于用于合并值列表/数组的 BigQuery JavaScript UDF的主要内容,如果未能解决你的问题,请参考以下文章

选择数组包含 bigquery 中多个值之一的行(最好使用 dbplyr)

值列表的 BigQUery 重复日期数组

MFC MDI CMFCPropertyGridProperty 添加数组用于下拉列表合并 MP4 标签数据

BigQuery LEFT JOIN 是加倍值

JSON 数组上的 BigQuery Enumerate-like 函数

从 Bigquery 中的 json 获取数组