Если у вас есть JSONB-поле, содержащее массив идентификаторов (ID), и вы хотите выбрать названия (или другие данные) из другой таблицы, соответствующие этим ID, можно использовать следующие подходы:
Пример данных
-
Таблица
products(товары):CREATE TABLE products ( id SERIAL PRIMARY KEY, name TEXT ); INSERT INTO products (id, name) VALUES (1, 'Laptop'), (2, 'Mouse'), (3, 'Keyboard'); -
Таблица
orders(заказы), где JSONB-полеproduct_idsсодержит массив ID товаров:CREATE TABLE orders ( id SERIAL PRIMARY KEY, product_ids JSONB ); INSERT INTO orders (id, product_ids) VALUES (1, '[1, 2]'), -- Заказ с товарами Laptop и Mouse (2, '[3]'); -- Заказ с товаром Keyboard
Задача
Для каждого заказа выбрать названия товаров, соответствующих ID из массива product_ids.
Решение 1: Использование jsonb_array_elements и JOIN
Функция jsonb_array_elements разворачивает JSONB-массив в набор строк, что позволяет использовать JOIN с таблицей products.
SELECT o.id AS order_id, p.name AS product_name
FROM orders o,
jsonb_array_elements_text(o.product_ids) AS product_id
JOIN products p ON p.id = product_id::int;Результат:
order_id | product_name
----------+--------------
1 | Laptop
1 | Mouse
2 | KeyboardПояснение:
jsonb_array_elements_text(o.product_ids)разворачивает массивproduct_idsв набор строк.product_id::intпреобразует строковое значение ID в целое число дляJOINс таблицейproducts.
Решение 2: Использование jsonb_to_recordset
Функция jsonb_to_recordset позволяет преобразовать JSONB-массив в таблицу с определёнными колонками.
SELECT o.id AS order_id, p.name AS product_name
FROM orders o,
jsonb_to_recordset(o.product_ids) AS product_id(id int)
JOIN products p ON p.id = product_id.id;Результат:
order_id | product_name
----------+--------------
1 | Laptop
1 | Mouse
2 | KeyboardПояснение:
jsonb_to_recordset(o.product_ids) AS product_id(id int)преобразует JSONB-массив в таблицу с одной колонкойid.JOINвыполняется по этой колонке.
Решение 3: Использование подзапроса и ANY
Если вам нужно получить названия товаров в виде массива для каждого заказа, можно использовать подзапрос и функцию array_agg.
SELECT o.id AS order_id,
array_agg(p.name) AS product_names
FROM orders o,
jsonb_array_elements_text(o.product_ids) AS product_id
JOIN products p ON p.id = product_id::int
GROUP BY o.id;Результат:
order_id | product_names
----------+--------------------
1 | {Laptop,Mouse}
2 | {Keyboard}Пояснение:
jsonb_array_elements_textразворачивает массив.array_agg(p.name)собирает названия товаров в массив для каждого заказа.
Решение 4: Использование WHERE с jsonb_exists
Если вам нужно выбрать заказы, содержащие определённый товар, можно использовать функцию jsonb_exists.
SELECT o.id AS order_id, p.name AS product_name
FROM orders o,
jsonb_array_elements_text(o.product_ids) AS product_id
JOIN products p ON p.id = product_id::int
WHERE jsonb_exists(o.product_ids, '2'); -- Выбрать заказы, содержащие товар с ID = 2Результат:
order_id | product_name
----------+--------------
1 | MouseПояснение:
jsonb_exists(o.product_ids, '2')проверяет, содержится ли ID2в массивеproduct_ids.
Решение 5: Использование WITH (CTE) для улучшения читаемости
Если запрос сложный, можно использовать общие табличные выражения (CTE) для улучшения читаемости.
WITH order_products AS (
SELECT o.id AS order_id, p.name AS product_name
FROM orders o,
jsonb_array_elements_text(o.product_ids) AS product_id
JOIN products p ON p.id = product_id::int
)
SELECT * FROM order_products;Результат:
order_id | product_name
----------+--------------
1 | Laptop
1 | Mouse
2 | KeyboardПояснение:
WITH order_products AS (...)создаёт временную таблицуorder_products, которую можно использовать в основном запросе.
Заключение
- Используйте
jsonb_array_elements_textилиjsonb_to_recordsetдля разворачивания JSONB-массива. - Применяйте
JOINдля связи с другой таблицей. - Если нужно агрегировать данные, используйте
array_agg. - Для сложных запросов применяйте CTE (
WITH).
Эти подходы помогут вам эффективно работать с JSONB-полями и выбирать данные из связанных таблиц.

Добавить комментарий