【问题标题】:Get most frequent value from a windowing function从窗口函数中获取最频繁的值
【发布时间】:2020-01-25 08:04:47
【问题描述】:

我有一个如下所示的 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

【问题讨论】:

  • 您能否详细说明您的逻辑,您如何获得预期的结果?如果没有一个最常见的角色怎么办?
  • 此时,我没有得到预期的结果,因为我没有到达那里得到它。你说得对,我不解释这个案子。如果没有一个最常用的角色,则角色应该用逗号分隔

标签: sql postgresql window-functions


【解决方案1】:

以下查询将为您工作。

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   

【讨论】:

  • 。 .您的代码很难遵循,但我认为它返回第一个值而不是最频繁的值。这是一个 dbfiddle:dbfiddle.uk/…。对于第一个用户,最频繁的角色从 1 变为 2。
  • 我不这么认为,但我会测试上述案例的代码并相应地更新答案。谢谢:)
【解决方案2】:

如果你真的想使用窗口功能,试试下面 -

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;

【讨论】:

    【解决方案3】:

    从技术上讲,您要计算的是众数(这是一个统计术语)。

    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;
    

    Here 是一个 dbfiddle。请注意,我添加了一些行来举例说明运行模式的变化。

    这不会特别有效,但(user_id, date, role) 上的索引应该会有所帮助。

    如果您只有少数几个角色,那么可能会有更有效的解决方案。如果是这种情况并且性能存在问题,请提出新问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 2013-02-14
      • 1970-01-01
      • 1970-01-01
      • 2020-11-22
      • 1970-01-01
      相关资源
      最近更新 更多