刚看到这个题目,作者表示一脸懵圈+满脸疑惑,啥?SQL还能求解这种问题,要求解这个问题,怎么确定同时在线的时间点?确定了时间点又怎么确定那时候在线人数有多少?想到这里,直接茫然加倍,因为题目中给的时间是一个横向的序列,他是一个横向的由时间段构成的时间轴,用户A,登录时间,退出时间,用户B,登录时间,退出时间,一个用户对应多个时间点,这样要求解这个问题似乎很难,因为我们似乎需要让每一个用户的在线时间段时间去做个交集,如图所示,如果要得到这个时间点,难,很难!
在观摩了各位大神的思想以后,我似乎发现了一个新大陆,既然横向的时间段构成的时间轴不太好处理,那何不给他做成一个纵向的时间点构成的时间序列,让每个客户登录的时间和退出时间变成两个不同的时间点,按照时间从小到大的顺序有序排列,登录的时候就给在线人数+1,退出的时候在线人数-1,这样的话,每一个时间点都会有一个在线人数,如图所示
怎么样,这么一看,你是不是有点豁然开朗了,此时,某个课程的同时在线人数,是不是就转变成了按照一个由用户的登录和退出时间组成的有序的时间序列缩对应的在线人数的累加问题了,用窗口函数sum()轻松解决!下面看一下整体的解题思路
第一步,将上课情况表attend_tb的登录时间和退出时间进行纵向拼接,生成零时表a。由于每一个user_id都有一个登录时间和退出时间,所以每一个user_id都有两条记录,要这两条记录都保存不被去重,则要使用union all的拼接方式,并且在拼接的时候将登录每个user_id登录行为标记为1的uv,退出的记录标记为-1,即在某个时刻,每进来一个用户,sum(vu)值都会+1,每出去一个用户,sum(uv)的值都会-1
第一步实现结果
第二步,将纵向拼接后的临时表a,以课程id进行开窗,并以时间从小到大排列,则某刻的同时在线人数为每个课程id的在线人数用
窗口函数sum进行累加操作后的值,如果时间相同,则对多条记录同时进行累加,并将查询结果生成临时表b
第二步实现结果
第三步,以临时表b为基础,对课程id进行分组聚合,max(在线人数)得到每门课程的最大在线人数值,然后将结果生成临时表c,用于后续拼接得到课程名称
第三步实现结果
第四步,用临时表c与课程表course_tb进行拼接,得到course_id对应的课程名称,得到最终结果
第四步实现结果
为防止各位大佬偷懒,此处只展示代码截图,有以上步骤,我相信各位聪明的大佬肯定能靠自己完成这些代码