Извлечь в несколько столбцов из JSON с PostgreSQL - PullRequest
1 голос
/ 18 июня 2020

У меня есть столбец item_id, содержащий данные в структуре JSON (например?).

+----------+---------------------------------------------------------------------------------------------------------------------------------------+
|     id   |                                                                item_id                                                                |
+----------+---------------------------------------------------------------------------------------------------------------------------------------+
|    56711 | {itemID":["0530#2#1974","0538\/2#2#1974","0538\/3#2#1974","0538\/18#2#1974","0539#2#1974"]}"                                          |
|    56712 | {itemID":["0138528#2#4221","0138529#2#4221","0138530#2#4221","0138539#2#4221","0118623\/2#2#4220"]}"                                  |
|    56721 | {itemID":["2704\/1#1#1356"]}"                                                                                                         |
|    56722 | {itemID":["0825\/2#2#3349","0840#2#3349","0844\/10#2#3349","0844\/11#2#3349","0844\/13#2#3349","0844\/14#2#3349","0844\/15#2#3349"]}" |
|    57638 | {itemID":["0161\/1#2#3364","0162\/1#2#3364","0163\/2#2#3364"]}"                                                                       |
|    57638 | {itemID":["109#1#3364","110\/1#1#3364"]}"                                                                                             |
+----------+---------------------------------------------------------------------------------------------------------------------------------------+

Мне нужно, чтобы последние четыре цифры перед каждой запятой (если есть) и последние 4 цифры были выделены и разделены на отдельные столбцы. разрешена только одна строка результата с идентификатором 57638.

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

+----------+-----------+-----------+
|    id    | item_id_1 | item_id_2 |
+----------+-----------+-----------+
|    56711 |      1974 |           |
|    56712 |      4220 |      4221 |
|    56721 |      1356 |           |
|    56722 |      3349 |           |
|    57638 |      3364 |      3365 |
+----------+-----------+-----------+

В результатах может быть довольно много столбцов 'item_id_%'.

Ответы [ 2 ]

0 голосов
/ 18 июня 2020
with the_table (id, item_id) as (
values
(56711, '{"itemID":["0530#2#1974","0538\/2#2#1974","0538\/3#2#1974","0538\/18#2#1974","0539#2#1974"]}'),
(56712, '{"itemID":["0138528#2#4221","0138529#2#4221","0138530#2#4221","0138539#2#4221","0118623\/2#2#4220"]}'),
(56721, '{"itemID":["2704\/1#1#1356"]}'),
(56722, '{"itemID":["0825\/2#2#3349","0840#2#3349","0844\/10#2#3349","0844\/11#2#3349","0844\/13#2#3349","0844\/14#2#3349","0844\/15#2#3349"]}'),
(57638, '{"itemID":["0161\/1#2#3364","0162\/1#2#3364","0163\/2#2#3364"]}'),
(57638, '{"itemID":["109#1#3365","110\/1#1#3365"]}')
)
select id
    ,(array_agg(itemid)) [1] itemid_1
    ,(array_agg(itemid)) [2] itemid_2
from (
    select distinct id
        ,split_part(replace(json_array_elements(item_id::json -> 'itemID')::text, '"', ''), '#', 3)::int itemid
    from the_table
    order by 1
        ,2
    ) t
group by id

ДЕМО

0 голосов
/ 18 июня 2020

Вы можете разложить массив json, получить последние 4 символа каждого элемента в виде числа, а затем выполнить условное агрегирование:

select 
    id,
    max(val) filter(where rn = 1) item_id_1,
    max(val) filter(where rn = 2) item_id_2
from (
    select
        id,
        right(val, 4)::int val,
        dense_rank() over(partition by id order by right(val, 4)::int) rn
    from mytable t
    cross join lateral jsonb_array_elements_text(t.item_id -> 'itemID') as x(val)
) t
group by id

Вы можете добавить дополнительные условные max() s к внешнему запрос для обработки большего количества возможных значений.

Демонстрация на DB Fiddle :

   id | item_id_1 | item_id_1
----: | --------: | --------:
56711 |      1974 |      <em>null</em>
56712 |      4220 |      4221
56721 |      1356 |      <em>null</em>
56722 |      3349 |      <em>null</em>
57638 |      3364 |      3365
...