#arrays #json #postgresql
Вопрос:
Я работаю в Postgres V11 и у меня есть таблица с полем (typeid) типа int4.
У меня также есть данные JSONB, которые я получаю из другой таблицы и сохраняю в локальной переменной.
Эти данные выглядят следующим образом
{"Types":[{"Category": "a", "TypeID": 26}, {"Category": "a", "TypeID": 27}, {"Category": "b", "TypeID": 28}, {"Category": "c", "TypeID": 30}, {"Category": "d", "TypeID": 29}]}
Запрос, который я пытаюсь написать, таков
SELECT * FROM table WHERE typeid is contained in this json data
Итак, я хочу, чтобы строки в таблице возвращались только в том случае, если идентификатор типа указан в массиве json.
Я пробовал разные комбинации этого, но еще не нашел ничего, что работало бы.
SELECT * FROM table WHERE typeid @> ANY (jsondata -> 'Types' -> 'TypeID')
Jsondata — > «Типы», похоже, возвращает только массив, но я, похоже, не могу понять, как указать, что я хочу сравнить со значением TypeID в объекте.
Postgres продолжает возвращаться
ОШИБКА: для ЛЮБОГО/ВСЕГО (массива) требуется массив с правой стороны
Итак, я попытался вернуть только массив, но он не знает, с чем сравнивать.
Спасибо за помощь!
Комментарии:
1. «хранение в локальной переменной» Локально для чего?
2. Это часть более крупной функции Postgres, поэтому, в частности, данные хранятся в переменной функции jsonb и не существуют в той же таблице, в которой я выбираю. Пример данных json представляет собой упрощенную версию того, с чем я имею дело, но единственное поле, которое меня интересует в этой части, — это TypeID
Ответ №1:
ЛЮБОЙ принимает массив PostgreSQL, а не массив JSON. Поскольку массивы JSON могут иметь разнородные типы, они не являются тривиально конвертируемыми в массивы PostgreSQL. Вы можете создать функцию справки для выполнения этого преобразования.
create function jsonb_to_intarray(jsonb,property text) returns int[] immutable parallel safe language SQL as $
select array_agg((x->>$2)::int) from jsonb_array_elements($1) f(x)
$;
И затем:
SELECT * FROM table WHERE typeid =ANY (jsonb_to_intarray(jsondata -> 'Types', 'TypeID'));
Ответ №2:
Нет единого оператора, которым вы могли бы воспользоваться. Вам нужно будет отменить проверку массива и протестировать каждый элемент:
select t.*
from the_table t
where exists (select *
from jsonb_array_elements(t.jsondata -> 'Types') as j(element)
where j.element ? 'TypeID')
Это приведет к списку строк, в которых содержится хотя бы один элемент массива TypeID
.