Извлечение данных JSON в простые столбцы - PullRequest
1 голос
/ 06 ноября 2019

Я унаследовал таблицу, которая содержит столбец, который выглядит примерно так:

field_a::json
=============
{'a':['1', '2']}
{'b':['foo', 'bar']}
{'a':[null, '3']}

По сути, я хочу преобразовать это в нечто более пригодное для использования в представлении или подобном. Существует только один ключ, а данные всегда представляют собой массив из двух элементов. Это то, к чему я стремлюсь:

field|value1|value2
===================
a    |     1|     2
b    |   foo|   bar
c    |  null|     3

Как я могу запросить это, если я не знаю названия ни одной из клавиш в игре здесь? Это на PG11

Ответы [ 2 ]

1 голос
/ 07 ноября 2019

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

create view view_of_my_table as
select id, key::text, value->>0 as value1, value->>1 as value2
from my_table
cross join jsonb_each(field_a)

select *
from view_of_my_table

 id | key | value1 | value2 
----+-----+--------+--------
  1 | a   | 1      | 2
  2 | b   | foo    | bar
  3 | c   |        | 3
(3 rows)    

Обратите внимание, что каждый запрос на выборку в представлении подразумевает запрос исходной таблицы с помощью функции jsonb_each(), так что это не самый эффективный способ,Для повышения производительности вы можете использовать материализованное представление и обновлять его после любой вставки / обновления исходной таблицы.

Прямая демонстрация в db <> fiddle.

0 голосов
/ 06 ноября 2019

Вероятно, ужасно неэффективно, но это делает работу:

DROP TABLE IF EXISTS source_table;
CREATE TEMP TABLE source_table ( field_a JSONB );

DROP TABLE IF EXISTS target_table;
CREATE TEMP TABLE target_table ( field TEXT, value1 JSONB, value2 JSONB );

INSERT INTO source_table VALUES
    ('{"a":["1", "2"]}'),   
    ('{"b":["foo", "bar"]}'),
    ('{"a":[null, 3]}');

INSERT INTO target_table
SELECT
    tmp.obj->>'key',
    COALESCE( TO_JSONB(((tmp.obj->'value')::JSONB)->0), 'null' ),
    COALESCE( TO_JSONB(((tmp.obj->'value')::JSONB)->1), 'null' )
FROM (
    SELECT TO_JSON(x) obj FROM (SELECT JSONB_EACH(field_a) x FROM source_table) AS x
) AS tmp;

SELECT * FROM target_table;

приводит к:

field|value1|value2
===================
"a" |   "1"|   "2"|
"b" | "foo"| "bar"|
"a" |  null|     3|

Где value1 и value2 - это JSONB столбцы и null сохраняется как JSONB.

Кроме того, даже если вы указали, что каждый объект содержит только один ключ, приведенное выше решение будет работать независимо от того, сколько ключей оно содержит.

PosgreSQL 9.5+

...