BigQuery JavaScript UDF для объединения списков / массивов значений - PullRequest
0 голосов
/ 16 января 2020

Итак, у меня есть эти столбцы, col1 thru colx имеют тип STRING/TEXT:

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

Есть ли простой способ объединить и объединить эти значения, используя UDF, с результатом [{"a":1}, {"b":2}, {"c":3}]?

Сначала я подумал о конкатенации строк и замене регулярных выражений, но SQL было бы довольно многословно, поэтому я сейчас смотрю на JS UDF. Однако я заблудился, как это сделать с произвольным количеством столбцов / аргументов. Цените ваши мысли!

EDIT 1

Чтобы уточнить, для реализации UDF было бы идеально, если бы я мог выбрать произвольное количество аргументов в произвольном порядке, то есть

  • func(col1, col2) дает мне [{"a":1}, {"b":2}], а
  • func(col1, col2, col3) дает мне [{"a":1}, {"b":2}, {"c": 3}].

Ответы [ 2 ]

1 голос
/ 16 января 2020

Можно ли сделать аргументы селективными, скажем, я могу выбрать объединить (col1, col2) или объединить (col1, col2, col100)?

fun c (col1, col2) дает мне [{"a": 1}, {"b": 2}] и
fun c (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}"] 
1 голос
/ 16 января 2020

Ниже для BigQuery Standard 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}  

Очевидно, что вышеприведенное применимо для любого числа столбцов, если первый столбец - id и col1 thru colx are all of type STRING, как указано в вопросе. Иными словами, выше необходимо немного скорректировать - но это были бы довольно незначительные изменения ...

...