#sql #postgresql #jsonb
Вопрос:
У меня есть две таблицы, пользователи и симуляторы. Таблица пользователи содержит список сведений о пользователе с полем идентификатора автоматического увеличения. Таблица моделирования содержит подробные сведения о моделировании, а также список связанных пользователей. user_list
Столбец в таблице моделирования представляет собой jsonb
поле, содержащее список идентификаторов связанных пользователей.
Примеры двух таблиц приведены ниже:
Имя таблицы: пользователи
Данные:
ID name country age
---- ------ --------- -----
1 Jason USA 21
2 William England 40
3 Jake USA 34
.
.
.
(total 100,000 rows)
Название таблицы: моделирование
Данные:
ID simulation_name user_list datetime
---- --------------- ---------- ----------
1 sample1 [1,2] <some datetime>
2 sample2 [5,6] <some datetime>
.
.
.
Я могу получить данные, касающиеся моделирования конкретной страны, используя следующий запрос
SELECT * from simulations
WHERE ARRAY(SELECT JSONB_ARRAY_ELEMENTS(user_list)::bigint)
amp;amp; ARRAY(SELECT id FROM users
WHERE country = 'USA');
Это дает следующий ответ
ID simulation_name datetime user_list
---- --------------- ---------- ----------
1 sample1 <some datetime> [1,2]
2 sample4 <some datetime> [1,9,12]
.
.
.
Однако это не совсем то, что мне нужно. Мне нужно users_list
, чтобы столбец возвращал не только идентификаторы, но и объект json, содержащий сведения о каждом пользователе.
Это тот ответ, который мне действительно нужен:
ID simulation_name datetime user_list
--- ---------------- -------------- ------------
1 sample1 <some datetime> [{"id":1,"name":"Jason","country":"USA"},{"id":2,"name":"William","country":"England"}]
.
.
Как заменить идентификаторы пользователей фактическими данными пользователей в виде списка объектов JSON, чтобы получить вышеуказанный ответ?
(Я знаю, что это было бы намного проще, если бы я следовал структуре таблиц «многие ко многим», но из-за определенных бизнес-требований я должен следовать этому)
Ответ №1:
Вы можете использовать объединенный или коррелированный подзапрос для получения связанных сведений о пользователе, а также json_agg
для объединения связанных сведений о пользователе в массив json, как показано ниже.
Вы также можете использовать s.user_list @> u.id::text::jsonb
его для определения того, существует ли пользователь в списке.
Использование соединения
SELECT
s.id,
s.simulation_name,
s.datetime ,
json_agg(u.*) as user_list
FROM
simulations s
INNER JOIN
users u ON s.user_list @> u.id::text::jsonb AND
u.country='USA'
GROUP BY
s.id,s.simulation_name,s.datetime;
ID | имя_симуляции | дата-время | список пользователей |
---|---|---|---|
1 | образец 1 | какое-то время | [{«идентификатор»:1,»имя»:»Джейсон»,»страна»:»США»,»возраст»:21}] |
Использование коррелированного запроса
SELECT * FROM (
SELECT
s.id,
s.simulation_name,
s.datetime ,
(
SELECT json_agg(u.*)
FROM users u
WHERE s.user_list @> u.id::text::jsonb AND
u.country='USA'
) as user_list
FROM
simulations s
) t
WHERE t.user_list IS NOT NULL;
ID | имя_симуляции | дата-время | список пользователей |
---|---|---|---|
1 | образец 1 | какое-то время | [{«идентификатор»:1,»имя»:»Джейсон»,»страна»:»США»,»возраст»:21}] |
Просмотр рабочей демо-версии на DB Fiddle
Дайте мне знать, если что-то из этого вам подойдет.
Комментарии:
1. Я попробовал подход ОБЪЕДИНЕНИЯ, и он отлично работает. Я уже пробовал подобный подход ранее, но неправильно понял часть типизации, поэтому он не работал. Спасибо 🙂