Можно ли оптимизировать запрос?

Мне нужно получить данные чатов для пользователя и к этим данными добавить колонку с именем другого пользователя этого чата.

У меня получился такой запрос. Он работает, но, меня смущает дубликаты запросов и его многоуровневость.

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;
→ Ссылка