Нажмите: пошаговая демонстрация: db <> fiddle
WITH autos AS (
SELECT '{"cars": [{"name": "BMW", "year": 1991}, {"name": "Ford", "model": "Mustang"}, {"name": "Fiat"}, {"name": "VW", "model": "Golf", "year": 2000}, {"name": "VW", "model": ""}]}'::jsonb as data
)
SELECT
'Cars: ' || STRING_AGG(NULLIF(car ->> 'name', ''), ',') || ' // '
'Years: ' || STRING_AGG(NULLIF(car ->> 'year', ''), ',') || ' // '
'Models: ' || STRING_AGG(NULLIF(car ->> 'model', ''), ',')
FROM autos,
jsonb_array_elements(data->'cars') as car
Используя этот набор данных:
{
"cars": [
{
"name": "BMW",
"year": 1991
},
{
"name": "Ford",
"model": "Mustang"
},
{
"name": "Fiat"
},
{
"name": "VW",
"year": 2000,
"model": "Golf"
},
{
"name": "VW",
"model": ""
}
]
}
Вы видите: нет model
(== null
) для BMW
, нет year
для Ford
, вообще нет данных для Fiat
, все атрибуты для VW Golf
, пустое model
для второго VW
.
Сначала получите таблицу для всех данных:
SELECT
car ->> 'name' as name,
car ->> 'year' as year,
car ->> 'model' as model
FROM autos,
jsonb_array_elements(data->'cars') as car
Вы уже использовали функцию jsonb_array_elements()
, которая расширяет массив JSON. Оператор ->>
дает значение атрибутов (в данном случае каждого элемента массива) как text
.
Теперь вы можете нормализовать пустые значения (model
второго VW
, в этом случае) до NULL
с использованием NULLIF()
. Вы можете сделать значение равным NULL
, если оно пустое:
NULLIF(myvalue, '')
Это приведет вас к:
SELECT
NULLIF(car ->> 'name', '') as name,
NULLIF(car ->> 'year', '') as year,
NULLIF(car ->> 'model', '') as model
FROM autos,
jsonb_array_elements(data->'cars') as car
Теперь у вас больше нет пустых значений, но много NULL
values.
Теперь вы можете использовать STRING_AGG()
для агрегирования всех значений, как вы ожидаете. Подсказка в том, что STRING_AGG()
автоматически игнорирует NULL
значения, поэтому вам не нужно колебаться.
SELECT
STRING_AGG(NULLIF(car ->> 'name', ''), ',') as names,
STRING_AGG(NULLIF(car ->> 'year', ''), ',') as years,
STRING_AGG(NULLIF(car ->> 'model', ''), ',') as models
FROM autos,
jsonb_array_elements(data->'cars') as car
Теперь у вас есть только три столбца и одна строка. Каждое значение агрегируется в строку.
Наконец, вы хотите объединить их в одну строку. Для этого вы можете использовать CONCAT()
или оператор ||
:
SELECT
'Cars: ' || STRING_AGG(NULLIF(car ->> 'name', ''), ',') || ' // '
'Years: ' || STRING_AGG(NULLIF(car ->> 'year', ''), ',') || ' // '
'Models: ' || STRING_AGG(NULLIF(car ->> 'model', ''), ',')
FROM autos,
jsonb_array_elements(data->'cars') as car
Редактировать:
Уточненные данные:
{
"cars": [
{
"name": "BMW"
},
{
"name": "Ford"
},
{
"name": "Fiat"
}
],
"dealers": [
{
"dealership": "LHM"
},
{
"dealership": "Camp"
},
{
"dealership": "HMA"
}
]
}
Нажмите: demo: db <> fiddle
SELECT
'Cars: ' || s1.names || ' // Dealers: ' || s2.dealerships
FROM
autos,
LATERAL (SELECT string_agg(c ->> 'name', ',') as names FROM jsonb_array_elements(data->'cars') as c) s1,
LATERAL (SELECT string_agg(d ->> 'dealership', ',') as dealerships FROM jsonb_array_elements(data->'dealers') as d) s2
В этом случае вам необходимо расширить и объединить массивы перед присоединением. Пожалуйста, добавьте функцию NULLIF()
в соответствующие столбцы, как сделано выше.