Технически, то, что вы пытаетесь вычислить, это режим (это статистический термин).
Postgres имеет встроенный mode()
функция. Увы, он не работает так, как вам нужно в качестве оконной функции, поэтому он мало помогает.
Я бы порекомендовал использовать боковое соединение:
select t.*, m.role
from t left join lateral
(select t2.role
from t t2
where t2.user_id = t.user_id and
t2.date < t.date
group by t2.role
order by count(*) desc,
max(date) desc -- in the event of ties, use the most recent
limit 1
) m
on 1=1
order by user_id, date;
Здесь это дб <> скрипка Обратите внимание, что я добавил несколько строк, чтобы привести пример изменения режима работы.
Это не будет особенно эффективно, но индекс (user_id, date, role)
должен помочь.
Если у вас есть только Горстка ролей, возможно, есть более эффективные решения. Если это так, а производительность - проблема, задайте новый вопрос.