SQL запрос не показанных анкет

У меня есть код, который по запросу выдает пользователю случайную анкету для знакомства. В качестве базы используется Postgresql v13 на Heroku

В таблице profiles хранятся анкеты (ид, имя, ид универа), в таблице uni хранятся данные об университетах (ид, название, расположение).

SELECT * 
FROM profiles p 
INNER JOIN uni u ON u.uni_id = p.uni_id 
WHERE NOT user_id='{message.from_user.id}' 
ORDER BY RANDOM() LIMIT 1

Как можно сделать что-то на подобии "истории" и не показывать тому же самому пользователю одну и ту же самую анкету? Пользователей несколько


Ответы (1 шт):

Автор решения: Alexander Pavlov

Я предполагаю, что {message.from_user.id} это ID текущего юзера, которому показывают результаты.

Тогда запрос на выборку и вставку в таблицу seen_by ("уже показывали") можно объединить

create table _uni (
    uni_id int
);

create table _profiles (
    user_id int,
    uni_id int
);

create table _seen_by (
    user_id int,
    seen_by_id int
);

insert into _uni(uni_id) select 1 union select 2 union select 3;
insert into _profiles(user_id, uni_id) select 1,1 union select 2,2 union select 3,3 union select 4,1 union select 5,2 union select 6,3;

-- этот запрос найдёт профили, которые текущий юзер ещё не видел,
-- возьмёт из них один случайный
-- зарегистрирует просмотр в таблице seen_by
-- и вернёт result set
with profiles_to_display as (
    SELECT *
    FROM _profiles p
    WHERE 
    NOT user_id = '{message.from_user.id}'
    AND user_id NOT IN (
      select sb.user_id from _seen_by sb where sb.seen_by_id = '{message.from_user.id}' 
    )
    ORDER BY RANDOM() LIMIT 1
), inserted as (
    insert into _seen_by(user_id, seen_by_id) 
    select user_id, '{message.from_user.id}' 
    from profiles_to_display 
    returning user_id
) select * from
    profiles_to_display
    inner join inserted using(user_id) -- triggers insertion
    INNER JOIN _uni u USING (uni_id);

На самом деле, исключать из показа навсегда - плохая идея. Я бы добавил таймстамп в таблицу seen_by и чистил старые (например, вставленные больше 7 дней назад) записи каждую ночь.

→ Ссылка