Можно ли оптимизировать запрос?
Мне нужно получить данные чатов для пользователя и к этим данными добавить колонку с именем другого пользователя этого чата.
У меня получился такой запрос. Он работает, но, меня смущает дубликаты запросов и его многоуровневость.
PostgreSQL 14
select c.*, name
from chats c
left join (
select concat(u.first_name, ' ', u.last_name) as name, ip.chat_id
from users u
left join chat_participants ip on u.id = ip.user_id
where ip.user_id != 1 and ip.chat_id in (
select cp.chat_id
from chat_participants cp
where cp.user_id = 1 and cp.is_deleted = false -- duplicate
)
) p on p.chat_id = c.id
where c.id in(
select cp.chat_id
from chat_participants cp
where cp.user_id = 1 and cp.is_deleted = false -- duplicate
);
-- Альтернативный вариант
select c.*,
concat(u.first_name, ' ', u.last_name) as name
from chats c
inner join chat_participants icp on icp.chat_id = c.id and icp.user_id = 1 and icp.is_deleted = false
left join chat_participants as ocp on ocp.chat_id = c.id and ocp.user_id != 1 and ocp.is_deleted = false
left join users u on u.id = ocp.user_id;
Можно ли его оптимизировать? И как это сделать?
Ожидаемый результат, список чатов для user с id = 1, где присутствует колонка name с именем второго участника.
chats
create table if not exists chats
(
id serial primary key,
creator_id int not null,
created_at timestamptz not null default now(),
foreign key (creator_id)
references users (id)
);
insert into chats (creator_id) values (1);
chat_participants
create table if not exists chat_participants
(
chat_id int not null,
user_id int not null,
is_deleted bool default false,
history_offset int default null,
primary key (chat_id, user_id),
foreign key (chat_id)
references chats (id) on delete cascade,
foreign key (user_id)
references users (id) on delete cascade
);
insert into chat_participants (chat_id, user_id) values (1, 1), (1, 2);
users
create table users
(
id serial primary key,
first_name varchar(80) not null,
last_name varchar(80) not null,
created_at timestamptz not null default now(),
deleted_at timestamptz
);
insert into users(first_name, last_name) values ('John', 'Doe'),
('Stepan', 'Vishnya');
Ответы (1 шт):
Автор решения: Yitzhak Khabinsky
→ Ссылка
Пожалуйста, попробуйте следующее решение.
SQL
select c.*, concat(u.first_name, ' ', u.last_name) as name
from chats c
LEFT OUTER JOIN chat_participants cp on c.id = cp.chat_id
INNER JOIN users u ON u.id = cp.user_id
where u.id != 1;
