利用SUM窗口函数找到同一时刻内的最大计数

每篇文章同一时刻最大在看人数

http://www.nowcoder.com/practice/fe24c93008b84e9592b35faa15755e48

时间:37ms 内存:6384KB

本题需求不难理解,难点在于如何计算瞬时的最大计数(在看人数)

首先,我们自然会想到常见的编码+联立。在此对原表in_time和out_time进行编码,in为观看人数+1, out为观看人数-1,进行两次SELECT联立,并按artical_id升序,时间戳升序:

代码:

    SELECT 
      artical_id, in_time dt, 1 diff
    FROM tb_user_log
    WHERE artical_id != 0
    UNION ALL
    SELECT 
      artical_id, out_time dt, -1 diff
    FROM tb_user_log
    WHERE artical_id != 0
    ORDER BY 1,2
    
结果:

9001|2021-11-01 10:00:00|1
9001|2021-11-01 10:00:01|1
9001|2021-11-01 10:00:09|1
9001|2021-11-01 10:00:11|-1
9001|2021-11-01 10:00:28|1
9001|2021-11-01 10:00:38|-1
9001|2021-11-01 10:00:51|1
9001|2021-11-01 10:00:58|-1
9001|2021-11-01 10:00:59|-1
9001|2021-11-01 10:01:50|-1
9002|2021-11-01 11:00:45|1
9002|2021-11-01 11:00:55|1
9002|2021-11-01 11:01:11|-1
9002|2021-11-01 11:01:24|-1

意义:

某篇文章artical_id,在给定的时间戳dt的,瞬时观看人数变化diff

到这一步,本题的解法基本就明朗了:

我们考虑使用SUM窗口函数,按文章id维度,统计按时间戳升序的观看人数变化情况:

代码:

  SELECT
    artical_id,
    dt,
    SUM(diff) OVER(PARTITION BY artical_id ORDER BY dt) instant_viewer_cnt
  FROM (
    SELECT 
      artical_id, in_time dt, 1 diff
    FROM tb_user_log
    WHERE artical_id != 0
    UNION ALL
    SELECT 
      artical_id, out_time dt, -1 diff
    FROM tb_user_log
    WHERE artical_id != 0) t1 
 
结果:
 
9001|2021-11-01 10:00:00|1
9001|2021-11-01 10:00:01|2
9001|2021-11-01 10:00:09|3
9001|2021-11-01 10:00:11|2
9001|2021-11-01 10:00:28|3
9001|2021-11-01 10:00:38|2
9001|2021-11-01 10:00:51|3
9001|2021-11-01 10:00:58|2
9001|2021-11-01 10:00:59|1
9001|2021-11-01 10:01:50|0
9002|2021-11-01 11:00:45|1
9002|2021-11-01 11:00:55|2
9002|2021-11-01 11:01:11|1
9002|2021-11-01 11:01:24|0

意义:

某篇文章artical_id,在给定的时间戳dt的,瞬时累计观看人数instant_viewer_cnt

然后到了本题的坑点。

题目要求在瞬时统计时遵循【先进后出】:如果同一时刻有进入也有离开时,先记录用户数增加,再记录减少。

因此在ORDER BY层面,在遵循dt升序的同时,还要遵循先+1,再-1的原则,即diff DESC:

SUM(diff) OVER(PARTITION BY artical_id ORDER BY dt, diff DESC)

——————————————————————————————————

步骤拆解:

  1. 对原表编码并联立;
  2. 按artical_id维度,dt升序 ,diff降序,对diff进行SUM开窗统计,得到每个artical_id的瞬时观看人数instant_viewer_cnt;
  3. 最外层SELECT按artical_id聚合,通过MAX(instant_viewer_cnt)取出瞬时观看最大值max_uv,并排序。

——————————————————————————————————

完整代码如下:


SELECT
  artical_id,
  MAX(instant_viewer_cnt) max_uv
FROM (
  SELECT
    artical_id,
    SUM(diff) OVER(PARTITION BY artical_id ORDER BY dt, diff DESC) instant_viewer_cnt
  FROM (
    SELECT 
      artical_id, in_time dt, 1 diff
    FROM tb_user_log
    WHERE artical_id != 0
    UNION ALL
    SELECT 
      artical_id, out_time dt, -1 diff
    FROM tb_user_log
    WHERE artical_id != 0) t1 
) t2
GROUP BY 1
ORDER BY 2 DESC


本解法思路来源于@大大BIG_GUM的代码,在此表示感谢!

全部评论
临时增加的diff列 不参与union的去重么 如果参与的话就没有重复列 用union不是应该也可以么 可是我试了一下会报错
1 回复 分享
发布于 2022-03-02 17:05
请问下 1 diff 是什么意思
10 回复 分享
发布于 2021-12-04 15:58
太牛了,感觉我今天看懂了明天要我自己写一遍还是写不出来
8 回复 分享
发布于 2022-03-21 19:02
不是同一时间进入也可能存在同时阅读的情况啊
4 回复 分享
发布于 2022-06-13 11:13
你,是我的神!!!!!!!!!!!!
4 回复 分享
发布于 2022-04-29 17:51
请问先加一再减一还是先减一再加一不都是一样的吗,为啥要排序呢?
3 回复 分享
发布于 2022-03-30 21:35
妙蛙
3 回复 分享
发布于 2022-02-12 16:11
这个题难就难在思路上,把进的时间和出的时间整合成一列,排序后对diff进行求和计算得出同一时刻进出人数
1 回复 分享
发布于 2023-02-01 14:03 北京
思路很清晰,看完答案后拍案叫绝
1 回复 分享
发布于 2022-10-29 17:10 广东
看不懂。。
1 回复 分享
发布于 2022-07-13 23:47
"因此在ORDER BY层面,在遵循dt升序的同时,还要遵循先+1,再-1的原则,即diff DESC" ——想请问楼主这句话是什么意思,确实我order by dt没有加上 diff,运行的结果通不过
1 回复 分享
发布于 2022-06-23 17:05
问一下同一时刻不应该按照时间进行group by 吗 这里怎么直接就按照数据进入时间段来进行了
1 回复 分享
发布于 2022-06-19 10:38
最后的 order by 1,2是什么意思呢?
1 回复 分享
发布于 2022-05-18 11:19
太赞了!学到了学到了!
点赞 回复 分享
发布于 04-27 16:36 北京
select artical_id, max(sum(uv)over(partition by artical_id order by event_time,uv desc)) as max_uv from (select artical_id,in_time as event_time,1 as uv from tb_user_log union all select artical_id,out_time as event_time,-1 as uv from tb_user_log) t1 where artical_id !=0 group by artical_id order by max_uv desc 请问这样为什么不行呢
点赞 回复 分享
发布于 2024-04-18 11:39 辽宁
想问下本题是排除了 “同一时刻 一个人的id出现两次吗 比如某时刻点开了 但没看挂在那里 又从另一个页面再次进来这个文章 那么原先第一次进的时候有记录还在看 第二次也在观看这个文章 本文章观看人数为2” 这个情况忽略了是吗 一个用户id每次只能看一个文章?
点赞 回复 分享
发布于 2024-03-04 13:30 香港
这思路是怎么想到的,太厉害了
点赞 回复 分享
发布于 2023-10-08 17:20 上海
提问:问什么不能直接写select artical_id,max(sum(diff) over(partition by......,而要再写个select查询呢?前面好像有题可以直接俄写sum(sum()) over(partition by.... 错误提示:Expression #1 of PARTITION BY or ORDER BY clause of window '' is not in GROUP BY clause and contains nonaggregated column 'a.t' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
点赞 回复 分享
发布于 2023-08-18 18:42 河南
牛啊
点赞 回复 分享
发布于 2023-08-04 16:15 陕西
求问 为什么在union的时候要限制 artical_id<>0 啊,有什么特别的意义吗?
点赞 回复 分享
发布于 2023-07-23 11:14 广东

相关推荐

点赞 评论 收藏
分享
评论
446
53
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务