Получить наиболее частое значение из оконной функции - PullRequest
0 голосов
/ 25 января 2020

У меня есть таблица SQL, которая выглядит следующим образом:

user_id role    date
1       1       2019-11-26 21:20:54.397+00
1       2       2019-11-27 22:46:28.923+00
2       1       2019-12-06 22:17:53.925+00
2       3       2019-12-13 00:12:28.006+00
3       1       2019-11-25 21:57:17.701+00
3       1       2019-12-06 20:48:28.314+00
3       1       2019-12-15 23:59:06.81+00
4       3       2019-12-04 15:26:10.639+00
4       3       2019-11-22 19:20:01.025+00
4       3       2019-11-25 12:38:53.169+00

Я хотел бы получить наиболее частую роль в соответствии с прошлыми датами и использованием. Результат должен выглядеть так:

user_id role    date                        most_frequent_role
1       1       2019-11-26 21:20:54.397+00  NULL
1       2       2019-11-27 22:46:28.923+00  1
2       1       2019-12-06 22:17:53.925+00  NULL
2       3       2019-12-13 00:12:28.006+00  1
3       1       2019-11-25 21:57:17.701+00  NULL
3       1       2019-12-06 20:48:28.314+00  1
3       1       2019-12-15 23:59:06.81+00   1
4       3       2019-12-04 15:26:10.639+00  NULL
4       3       2019-11-22 19:20:01.025+00  3
4       3       2019-11-25 12:38:53.169+00  3

Ответы [ 3 ]

0 голосов
/ 25 января 2020

Если вы строго хотите go с оконной функцией, попробуйте ниже -

SELECT user_id
      ,role
      ,date
      ,CASE WHEN date = MIN(date) OVER(PARTITION BY user_id ORDER BY date)
                 THEN NULL
            ELSE MIN(role) OVER(PARTITION BY user_id) END MOST_FREQUENT_ROLE 
FROM YOUR_TABLE;
0 голосов
/ 25 января 2020

Технически, то, что вы пытаетесь вычислить, это режим (это статистический термин).

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) должен помочь.

Если у вас есть только Горстка ролей, возможно, есть более эффективные решения. Если это так, а производительность - проблема, задайте новый вопрос.

0 голосов
/ 25 января 2020

Следующий запрос будет работать для вас.

select test.user_id,test.role,test.role_date, 
case when test.role_date in 
(select min(role_date) from test group by user_id) then NULL 
else t.role end as MOST_FREQUENT_ROLE 
from 
(select user_id,min(role) as role from test group by user_id
)t 
join test on t.user_id=test.user_id
order by user_id,role_date

Вывод

USER_ID ROLE    ROLE_DATE   MOST_FREQUENT_ROLE
1         1     26-NOV-19    - 
1         2     27-NOV-19    1
2         1     06-DEC-19    - 
2         3     13-DEC-19    1
3         1     25-NOV-19    - 
3         1     06-DEC-19    1
3         1     15-DEC-19    1
4         3     22-NOV-19    - 
4         3     25-NOV-19    3
4         3     04-DEC-19    3   
...