Большой запрос SQL объединение или связывание значений в конвейерных строках или массивах строк - PullRequest
1 голос
/ 17 марта 2020

У меня есть два поля в большой таблице BQ. Оба поля являются строками. Обе строки отформатированы так, чтобы представлять несколько значений, разделенных каналами, одинаковое количество значений в каждой строке. Мне нужно связать каждое значение в первом наборе с каждым значением во втором наборе. Например:

id   names     nums

x    "a|b|c"   "3|9|5"
y    "d"       "1"
z    "e|f"     "4|7"

Мне нужно получить такой результат, как:

x,a,3
x,b,9
x,c,5
y,d,1
z,e,4
z,f,7

Вторая строка ввода - это последовательность чисел, но я не против, если она выйдет как цифра c или строка (я выясню приведение).
Кажется очевидным, что мне нужно использовать split (), в какой-то момент можно преобразовать строки в массивы, но как я могу объединить массивы слева направо? а не по длине?
Я знаю, что могу использовать двойное гнездо с индексом и выбирать только там, где индексы равны, однако я не хочу использовать этот метод, потому что он делает уже большую таблицу ввода массивной (до выбираем равные индексы).
Спасибо за любые мысли!

Ответы [ 2 ]

1 голос
/ 17 марта 2020

Вот один метод, который генерирует серию индексов и использует массивы для извлечения значений:

select id, split(names, '|')[safe_ordinal(n)] as names, 
       split(nums, '|')[safe_ordinal(n)] as nums
from (select 'x' as id, 'a|b|c' as names, '3|9|5' as nums union all
      select 'y', 'd', '1' union all
      select 'z', 'e|f', '4|7'
     ) t cross join
     unnest(generate_array(1, array_length(split(names, '|')))) as n;

Используется длина names для определения количества значений.

0 голосов
/ 17 марта 2020

Альтернативный вариант для BigQuery Standard SQL

#standardSQL
SELECT id, name, num
FROM `project.dataset.table`,
UNNEST(SPLIT(names, '|')) name WITH OFFSET
JOIN UNNEST(SPLIT(nums, '|')) num WITH OFFSET
USING(OFFSET)

Если применяется к образцам данных в вашем вопросе, как в примере ниже

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'x' id, 'a|b|c' names, '3|9|5' nums UNION ALL
  SELECT 'y', 'd', '1' UNION ALL
  SELECT 'z', 'e|f', '4|7' 
)
SELECT id, name, num
FROM `project.dataset.table`,
UNNEST(SPLIT(names, '|')) name WITH OFFSET
JOIN UNNEST(SPLIT(nums, '|')) num WITH OFFSET
USING(OFFSET)

результат равен

Row id  name    num  
1   x   a       3    
2   x   b       9    
3   x   c       5    
4   y   d       1    
5   z   e       4    
6   z   f       7    

Выше можно реорганизовать использование UDF, поэтому основной запрос становится простым и читабельным - как в следующем примере

#standardSQL
CREATE TEMP FUNCTION xxx(arr1 ANY TYPE, arr2 ANY TYPE) 
RETURNS ARRAY<STRUCT<name STRING, num STRING>> AS (
ARRAY(
  SELECT AS STRUCT el1, el2
  FROM UNNEST(SPLIT(arr1, '|')) el1 WITH OFFSET
  JOIN UNNEST(SPLIT(arr2, '|')) el2 WITH OFFSET
  USING(OFFSET)
));
SELECT id, x.*
FROM `project.dataset.table`, UNNEST(xxx(names, nums)) x

, очевидно, с тем же выводом

...