Postgres 9.4 или новее
Postgres 9.4, очевидно вдохновленный этим постом , добавил недостающие функции:
спасибо Laurence Rowe за патч и Andrew Dunstan за коммит!
Развернуть массив JSON. Затем используйте array_agg()
конструктор ARRAY или для построения массива Postgres из него. Или string_agg()
построить text
строку .
Агрегируйте неопубликованные элементы по строке в LATERAL
или соответствующем подзапросе. Тогда оригинальный порядок сохраняется, и нам не нужен ORDER BY
, GROUP BY
или даже уникальный ключ во внешнем запросе. Видеть:
Замените «json» на «jsonb» jsonb
во всем следующем коде SQL.
SELECT t.tbl_id, d.list
FROM tbl t
CROSS JOIN LATERAL (
SELECT string_agg(d.elem::text, ', ') AS list
FROM json_array_elements_text(t.data->'tags') AS d(elem)
) d;
Краткий синтаксис:
SELECT t.tbl_id, d.list
FROM tbl t, LATERAL (
SELECT string_agg(value::text, ', ') AS list
FROM json_array_elements_text(t.data->'tags') -- col name default: "value"
) d;
Связанный:
Конструктор ARRAY в коррелированном подзапросе:
SELECT tbl_id, ARRAY(SELECT json_array_elements_text(t.data->'tags')) AS txt_arr
FROM tbl t;
Связанный:
Тонкое различие : null
элементы сохраняются в реальных массивах . Это невозможно в вышеупомянутых запросах, создающих text
строку, которая не может содержать null
значения. Истинное представление является массивом.
Функциональная оболочка
Для повторного использования, чтобы сделать это еще проще, инкапсулируйте логику в функции:
CREATE OR REPLACE FUNCTION json_arr2text_arr(_js json)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT json_array_elements_text(_js))';
Сделайте это функцией SQL , чтобы ее можно было вставлять в большие запросы.
Сделайте это IMMUTABLE
(потому что это так), чтобы избежать повторной оценки в больших запросах и разрешить это в выражениях индекса.
Вызов:
SELECT tbl_id, json_arr2text_arr(data->'tags')
FROM tbl;
дБ <> скрипка здесь
Postgres 9.3 или старше
Используйте функцию json_array_elements()
. Но мы получаем строки из двойных кавычек .
Альтернативный запрос с агрегацией во внешнем запросе. CROSS JOIN
удаляет строки с отсутствующими или пустыми массивами. Может также быть полезным для обработки элементов. Нам нужен уникальный ключ для агрегирования:
SELECT t.tbl_id, string_agg(d.elem::text, ', ') AS list
FROM tbl t
CROSS JOIN LATERAL json_array_elements(t.data->'tags') AS d(elem)
GROUP BY t.tbl_id;
Конструктор ARRAY, все еще с кавычками:
SELECT tbl_id, ARRAY(SELECT json_array_elements(t.data->'tags')) AS quoted_txt_arr
FROM tbl t;
Обратите внимание, что null
преобразуется в текстовое значение «ноль», в отличие от выше. Неправильно, строго говоря, и потенциально неоднозначно.
Бедный мужчина не цитирует trim()
:
SELECT t.tbl_id, string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM tbl t, json_array_elements(t.data->'tags') d(elem)
GROUP BY 1;
Получить одну строку из таблицы:
SELECT string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM tbl t, json_array_elements(t.data->'tags') d(elem)
WHERE t.tbl_id = 1;
Строки формируют коррелированный подзапрос:
SELECT tbl_id, (SELECT string_agg(trim(value::text, '"'), ', ')
FROM json_array_elements(t.data->'tags')) AS list
FROM tbl t;
ARRAY конструктор:
SELECT tbl_id, ARRAY(SELECT trim(value::text, '"')
FROM json_array_elements(t.data->'tags')) AS txt_arr
FROM tbl t;
Оригинальная (устаревшая) SQL Fiddle .
дБ <> скрипка здесь.
Связанный:
Примечания (устарели с 9.4)
Нам понадобится json_array_elements_text(json)
двойник json_array_elements(json)
для возврата правильных text
значений из массива JSON. Но этого, похоже, не хватает в предоставленном арсенале функций JSON . Или какая-то другая функция для извлечения text
значения из скалярного JSON
значения. Кажется, мне тоже не хватает этого.
Так что я импровизировал trim()
, но это не удастся для нетривиальных случаев ...
json_extract_path_text(your_column, 'tags')
то, что вы ищете?