У меня есть столбец, data
который содержит json
документ примерно так:
{
"name": "foo",
"tags": ["foo", "bar"]
}
Я хотел бы превратить вложенный tags
массив в объединенную строку ( foo, bar
). Это было бы легко возможно с array_to_string()
функцией в теории. Однако эта функция не работает с json
массивами. Поэтому мне интересно, как превратить этот json
массив в Postgres array
?
postgresql
postgresql-9.3
array
json
Christoph
источник
источник
json_extract_path_text(your_column, 'tags')
то, что вы ищете?Ответы:
Postgres 9.4 или новее
Postgres 9.4, очевидно вдохновленный этим постом , добавил недостающие функции:
спасибо Laurence Rowe за патч и Andrew Dunstan за коммит!
json_array_elements_text(json)
jsonb_array_elements_text(jsonb)
Развернуть массив JSON. Затем используйте
array_agg()
конструктор ARRAY или для построения массива Postgres из него. Илиstring_agg()
построитьtext
строку .Агрегируйте неопубликованные элементы по строке в
LATERAL
или соответствующем подзапросе. Тогда оригинальный порядок сохраняется, и нам не нуженORDER BY
,GROUP BY
или даже уникальный ключ во внешнем запросе. Видеть:Замените «json» на «jsonb»
jsonb
во всем следующем коде SQL.Краткий синтаксис:
Связанный:
Конструктор ARRAY в коррелированном подзапросе:
Связанный:
Тонкое различие :
null
элементы сохраняются в реальных массивах . Это невозможно в вышеупомянутых запросах, создающихtext
строку, которая не может содержатьnull
значения. Истинное представление является массивом.Функциональная оболочка
Для повторного использования, чтобы сделать это еще проще, инкапсулируйте логику в функции:
Сделайте это функцией SQL , чтобы ее можно было вставлять в большие запросы.
Сделайте это
IMMUTABLE
(потому что это так), чтобы избежать повторной оценки в больших запросах и разрешить это в выражениях индекса.Вызов:
дБ <> скрипка здесь
Postgres 9.3 или старше
Используйте функцию
json_array_elements()
. Но мы получаем строки из двойных кавычек .Альтернативный запрос с агрегацией во внешнем запросе.
CROSS JOIN
удаляет строки с отсутствующими или пустыми массивами. Может также быть полезным для обработки элементов. Нам нужен уникальный ключ для агрегирования:Конструктор ARRAY, все еще с кавычками:
Обратите внимание, что
null
преобразуется в текстовое значение «ноль», в отличие от выше. Неправильно, строго говоря, и потенциально неоднозначно.Бедный мужчина не цитирует
trim()
:Получить одну строку из таблицы:
Строки формируют коррелированный подзапрос:
ARRAY конструктор:
Оригинальная (устаревшая) SQL Fiddle .
дБ <> скрипка здесь.
Связанный:
Примечания (устарели с 9.4)
Нам понадобится
json_array_elements_text(json)
двойникjson_array_elements(json)
для возврата правильныхtext
значений из массива JSON. Но этого, похоже, не хватает в предоставленном арсенале функций JSON . Или какая-то другая функция для извлеченияtext
значения из скалярногоJSON
значения. Кажется, мне тоже не хватает этого.Так что я импровизировал
trim()
, но это не удастся для нетривиальных случаев ...источник
to_jsonb()
для преобразования массива-> JSONB.SELECT ARRAY(SELECT json_array_elements_text(_js))
Действительно ли гарантируется, что порядок массива сохранен? Разве оптимизатору не разрешено теоретически изменять порядок строк, выходящих из json_array_elements_text?PG 9.4+
Принятый ответ определенно то, что вам нужно, но для простоты вот помощник, который я использую для этого:
Тогда просто сделайте:
источник
Этот вопрос был задан в списках рассылки PostgreSQL, и я пришел к такому хакерскому способу преобразования текста JSON в текстовый тип PostgreSQL с помощью оператора извлечения полей JSON:
По сути, он преобразует значение в массив из одного элемента, а затем запрашивает первый элемент.
Другой подход заключается в использовании этого оператора для извлечения всех полей по одному. Но для больших массивов это, вероятно, медленнее, так как необходимо проанализировать всю строку JSON для каждого элемента массива, что приводит к сложности O (n ^ 2).
источник
Я протестировал несколько вариантов. Вот мой любимый запрос. Предположим, у нас есть таблица, содержащая поле id и json. Поле json содержит массив, который мы хотим превратить в массив pg.
Работает где угодно и быстрее других, но выглядит хилым)
Сначала массив json преобразуется как текст, а затем мы просто заменяем квадратные скобки на круглые скобки. Наконец, текст приводится как массив требуемого типа.
и если вы предпочитаете текстовые [] массивы
источник
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"
Я думаю, что вы должны добавить некоторые объяснения о том, как это должно работать.SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"
Это не такЭти несколько функций, взятые из ответов на этот вопрос , являются тем, что я использую, и они прекрасно работают
В каждом из них, объединяясь с пустым массивом, они обрабатывают случай, в котором я немного ломал голову, в том случае, если вы попытаетесь разыграть пустой массив из
json
/jsonb
без него, вы ничего не получите, вместо пустой массив ({}
), как и следовало ожидать. Я уверен, что есть некоторая оптимизация для них, но они оставлены для простоты объяснения концепции.источник