объединить столбцы, разделенные разделителем, в одной таблице - PullRequest
2 голосов
/ 07 мая 2020

У меня есть следующий набор данных

color_code   fav_color_code    color_code_name    fav_color_name 
1|2          5                 blue|white         black
3|4          7|9               green|red          pink|yellow

Мне нужно join первое значение color_code до первого значения color_code_name и второе значение color_code до второго значения color_code_name et c ..

code                color
1                   blue
2                   white
5                   black
3                   green
4                   red
7                   pink
9                   yellow

Я использую приведенный ниже код, но он выполняет перекрестное соединение, поскольку у меня нет id - join. Этот код работает, если я сопоставляю 2 столбца, но не несколько столбцов.

Может ли кто-нибудь помочь мне получить ожидаемый результат?

SELECT 
        t1.code AS code, 
        t2.color AS color, 
      FROM 
        (
          SELECT 
            c.value :: varchar AS code, 
            row_number() over(
              order by 
                code
            ) AS rownum 
          FROM 
            table, 
            lateral flatten (
              input => split(color_code, '|')
            ) c  
          UNION 
          SELECT 
            d.value :: varchar AS code, 
            row_number() OVER(
              ORDER BY 
                code
            ) AS rownum
            FROM 
            table, 
            lateral flatten (
              input => split(fav_color_code, '|')
            ) d 
        ) t1 
        JOIN (
          SELECT 
            f.value :: varchar AS color, 
            row_number() OVER(
              ORDER BY 
                color
            ) AS rownum 
          FROM 
            table, 
            lateral flatten (
              input => split(color_code_name, '|')
            ) f 
          UNION 
          SELECT 
            g.value :: varchar AS color, 
            row_number() OVER(
              ORDER BY 
                color
            ) AS rownum 
          FROM 
            table, 
            lateral flatten (
              input => split(fav_color_name, '|')
            ) g 
        ) t2 ON (t1.rownum = t2.rownum) 
      ORDER BY 
        t1.color

1 Ответ

1 голос
/ 07 мая 2020

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

ПРИМЕЧАНИЕ. Решение кода выполняется в Hive ( post не указывает никаких sql-query-engine), но в Hive почти все sql-standard.

Исходные данные

+--------------------+------------------------+-------------------------+------------------------+--+
| colors.color_code  | colors.fav_color_code  | colors.color_code_name  | colors.fav_color_name  |
+--------------------+------------------------+-------------------------+------------------------+--+
| 1|2                | 5                      | blue|white              | black                  |
| 3|4                | 7|9                    | green|red               | pink|yellow            |
+--------------------+------------------------+-------------------------+------------------------+--

Сначала мы создаем temp table с color ids, где мы объединяем code columns, split столбец в array, а затем explode array с rownumber

CREATE TABLE tc1 AS
SELECT ROW_NUMBER() OVER() AS rownum, CAST(color_id AS INT) as color_id
FROM colors
LATERAL VIEW EXPLODE(SPLIT(CONCAT(color_code,'|', fav_color_code),'\\|')) a1 AS color_id;

Мы создаем второй temp table с color names, и мы следуем подходу, как и раньше, но теперь мы объединяем color_name столбцы, split столбец в array, а затем explode array с rownumber

CREATE TABLE tc2 AS
SELECT ROW_NUMBER() OVER() AS rownum, color_name
FROM colors
LATERAL VIEW EXPLODE(SPLIT(CONCAT(color_code_name,'|', fav_color_name),'\\|')) a1 AS color_name;

мы join временные таблицы на rownum

SELECT color_id, color_name
FROM tc1
JOIN tc2 ON(tc1.rownum = tc2.rownum)
ORDER BY color_id;

Ожидаемый результат

+-----------+-------------+--+
| color_id  | color_name  |
+-----------+-------------+--+
| 1         | blue        |
| 2         | white       |
| 3         | green       |
| 4         | red         |
| 5         | black       |
| 7         | pink        |
| 9         | yellow      |
+-----------+-------------+--+

Выполнение того же самого за один снимок, хотя это не легкий вес запрос

SELECT tc1.color_id, tc2.color_name
FROM (SELECT ROW_NUMBER() OVER() AS rownum, CAST(color_id AS INT) as color_id
      FROM colors
      LATERAL VIEW EXPLODE(SPLIT(CONCAT(color_code,'|', fav_color_code),'\\|')) a1 AS color_id) AS tc1
JOIN (SELECT ROW_NUMBER() OVER() AS rownum, color_name
      FROM colors
      LATERAL VIEW EXPLODE(SPLIT(CONCAT(color_code_name,'|', fav_color_name),'\\|')) a1 AS color_name) AS tc2
ON(tc1.rownum = tc2.rownum)
ORDER BY tc1.color_id;

Ожидаемый результат

+---------------+-----------------+--+
| tc1.color_id  | tc2.color_name  |
+---------------+-----------------+--+
| 1             | blue            |
| 2             | white           |
| 3             | green           |
| 4             | red             |
| 5             | black           |
| 7             | pink            |
| 9             | yellow          |
+---------------+-----------------+--+
...