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 шт):
Я предполагаю, что {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 дней назад) записи каждую ночь.