游戏行业实战案例 5 :玩家在线分布

news2024/10/7 18:22:05

3ab8bdd353f320281fccdb77aa6ecbd7.png

【面试题】某游戏数据后台设有“登录日志”和“登出日志”两张表。

「登录日志」记录各玩家的登录时间和登录时的角色等级。 

961ca44388a09104d4e4c16d53d057c3.png

「登出日志」记录各玩家的登出时间和登出时的角色等级。

23530e6d0100def937602f0563dbb065.png

其中,「角色 id 」字段唯一识别玩家。

游戏开服前两天( 2022-08-13 至 2022-08-14 )的角色登录和登出日志如下

7d5341af52fef043b644f57fe7bd309e.png

7848d2cdbdbd1ff156ce96177453162d.png

一天中,玩家可以多次登录登出游戏,请使用 SQL 分析出以下业务问题:

请根据玩家登录登出的时间,统计在开服首日各玩家在线时长分布。

(如玩家登录后没有对应的登出日志,可以使用当天 23:59:59 作为登出时间,时间之间的计算可以考虑使用时间戳函数 unix_timestamp 。【区分在线时间段:0-30min ,30min-1h ,1-2h ,2-3h ,3-5h ,5h 以上;区间为左闭右开】)

问题 5 :

统计在开服首日各玩家在线时长分布,其中区分在线时间段:0-30min ,30min-1h ,1-2h ,2-3h ,3-5h ,5h 以上,区间为左闭右开,解释为大白话即为:统计2022-08-13,在线时间段在 0-30min 、30min-1h 、1-2h 、 2-3h 、3-5h 、5h 以上的玩家各有多少人。

统计人数使用 count() 函数,而玩家的在线时间段可以用 case when 子句进行条件判断,即使用 case when 子句判断各玩家的总在线时长在哪个在线时间段内:

case when 总在线时长_min>=0 and 总在线时长_min<30 then '0-30min'
when 总在线时长_min>=30 and 总在线时长_min<60 then '30min-1h'
when 总在线时长_min>=60 and 总在线时长_min<120 then '1-2h'
when 总在线时长_min>=120 and 总在线时长_min<180 then '2-3h'
when 总在线时长_min>=180 and 总在线时长_min<300 then '3-5h'
else '5h以上' end

将问题 4 中统计各玩家每天的总在线时长的查询结果设为临时表 d ,则判断开服首日,各玩家的总在线时长在哪个在线时间段内的 SQL 的书写方法:

select 角色id,
       (case when 总在线时长_min>=0 and 总在线时长_min<30 then '0-30min'
        when 总在线时长_min>=30 and 总在线时长_min<60 then '30min-1h'
        when 总在线时长_min>=60 and 总在线时长_min<120 then '1-2h'
        when 总在线时长_min>=120 and 总在线时长_min<180 then '2-3h'
        when 总在线时长_min>=180 and 总在线时长_min<300 then '3-5h'
        else '5h以上' end) as 在线时间段
from d
where 日期 = '2022-08-13';

利用 with…as 语句来封装临时表 d 的查询语句,则 SQL 的书写方法:

with d as
(with c as
(select a.角色id,a.日期,a.登录时间,
        (case when b.登出时间 is null then concat(a.日期,'23:59:59') else b.登出时间 end) as 登出时间
from
(select 角色id,日期,登录时间,rank() over(partition by 角色id,日期 order by 登录时间 asc) as 登录排名
from 登录日志) as a
left join
(select 角色id,日期,登出时间,rank() over(partition by 角色id,日期 order by 登出时间 asc) as 登出排名
from 登出日志) as b
on a.角色id = b.角色id and a.日期 = b.日期 and a.登录排名 = b.登出排名
)
select 角色id,日期,
sum(round((unix_timestamp(登出时间)- unix_timestamp(登录时间))/60,2)) as 总在线时长_min
from c
group by 角色id,日期
)
select 角色id,
       (case when 总在线时长_min>=0 and 总在线时长_min<30 then '0-30min'
        when 总在线时长_min>=30 and 总在线时长_min<60 then '30min-1h'
        when 总在线时长_min>=60 and 总在线时长_min<120 then '1-2h'
        when 总在线时长_min>=120 and 总在线时长_min<180 then '2-3h'
        when 总在线时长_min>=180 and 总在线时长_min<300 then '3-5h'
        else '5h以上' end) as 在线时间段
from d
where 日期 = '2022-08-13';

查询结果如下:

04d26f64f88569420477112fb5856746.png

现在我们来计算各在线时间段的玩家人数,同样,使用 group by 子句和 count() 函数即可实现。

将上述查询结果设为临时表 e ,则 SQL 的书写方法:

select 在线时间段,count(角色id) as 玩家人数
from e
group by 在线时间段;

将临时表 e 的查询语句代入,则 SQL 的书写方法:

with d as
(with c as
(select a.角色id,a.日期,a.登录时间,
        (case when b.登出时间 is null then concat(a.日期,'23:59:59') else b.登出时间 end) as 登出时间
from
(select 角色id,日期,登录时间,rank() over(partition by 角色id,日期 order by 登录时间 asc) as 登录排名
from 登录日志) as a
left join
(select 角色id,日期,登出时间,rank() over(partition by 角色id,日期 order by 登出时间 asc) as 登出排名
from 登出日志) as b
on a.角色id = b.角色id and a.日期 = b.日期 and a.登录排名 = b.登出排名
)
select 角色id,日期,
sum(round((unix_timestamp(登出时间)- unix_timestamp(登录时间))/60,2)) as 总在线时长_min
from c
group by 角色id,日期
)
select 在线时间段,count(角色id) as 玩家人数
from
(select 角色id,
       (case when 总在线时长_min>=0 and 总在线时长_min<30 then '0-30min'
        when 总在线时长_min>=30 and 总在线时长_min<60 then '30min-1h'
        when 总在线时长_min>=60 and 总在线时长_min<120 then '1-2h'
        when 总在线时长_min>=120 and 总在线时长_min<180 then '2-3h'
        when 总在线时长_min>=180 and 总在线时长_min<300 then '3-5h'
        else '5h以上' end) as 在线时间段
from d
where 日期 = '2022-08-13'
) as e
group by 在线时间段;

查询结果如下:

2c024b6924b28ce1d7517277b4784aad.png

可以看到,虽然我们已经得到了各在线时间段的玩家人数,但是在线时间段的排列是乱序的,查看分布情况不是很方便。因此,我们需要对在线时间段进行重新排序。

「在线时间段」这一列数据类型为字符串,无法用 order by 子句进行简单排序,那么如何对在线时间段进行重新排序呢?

可以使用 field() 函数。field() 函数是自定义排序函数,可以自定义排列顺序,使用方法为:

order by field(值,str1,str2,str3,str4,……,strn) asc/desc

意思为:

将值按照 str1 , str2 , str3 , str4 ,……, strn 的顺序升序(asc)或者降序排列(desc)。

将其应用在本问题中,则为:

order by field(在线时间段,'0-30min','30min-1h','1-2h','2-3h','3-5h','5h以上') asc

即:将在线时间段这一列的值按照 '0-30min' , '30min-1h' , '1-2h' , '2-3h' , '3-5h' , '5h以上' 的顺序升序排列。

将其代入上述 SQL 语句中,则统计开服首日,玩家的在线时长分布的完整 SQL 的书写方法为:

with d as
(with c as
(select a.角色id,a.日期,a.登录时间,
        (case when b.登出时间 is null then concat(a.日期,'23:59:59') else b.登出时间 end) as 登出时间
from
(select 角色id,日期,登录时间,rank() over(partition by 角色id,日期 order by 登录时间 asc) as 登录排名
from 登录日志) as a
left join
(select 角色id,日期,登出时间,rank() over(partition by 角色id,日期 order by 登出时间 asc) as 登出排名
from 登出日志) as b
on a.角色id = b.角色id and a.日期 = b.日期 and a.登录排名 = b.登出排名
)
select 角色id,日期,
sum(round((unix_timestamp(登出时间)- unix_timestamp(登录时间))/60,2)) as 总在线时长_min
from c
group by 角色id,日期
)
select 在线时间段,count(角色id) as 玩家人数
from
(select 角色id,
       (case when 总在线时长_min>=0 and 总在线时长_min<30 then '0-30min'
        when 总在线时长_min>=30 and 总在线时长_min<60 then '30min-1h'
        when 总在线时长_min>=60 and 总在线时长_min<120 then '1-2h'
        when 总在线时长_min>=120 and 总在线时长_min<180 then '2-3h'
        when 总在线时长_min>=180 and 总在线时长_min<300 then '3-5h'
        else '5h以上' end) as 在线时间段
from d
where 日期 = '2022-08-13'
) as e
group by 在线时间段
order by field(在线时间段,'0-30min','30min-1h','1-2h','2-3h','3-5h','5h以上') asc;

查询结果如下:

032b038d0d6feae2fd21469290da0101.png

【本题考点】

1、考察逻辑分析能力,即:如何将复杂问题拆解成容易解决的一个个子问题的能力;

2、考察排序窗口函数的灵活使用。在需要进行分组排序时,排序窗口函数往往是首选;

3、考察 case when 语句的灵活应用以及分组汇总时,group by 子句、聚合函数的搭配使用;

4、考察纵向联结和横向联结的使用。纵向联结使用 union 方法(union、union all),横向联结使用 join 方法(left join、innerjoin、right join);

5、考察多重子查询的应用以及 with…as 语句的应用。

75a95b2604b8712eb433e133ff8ec625.jpeg

 ⬇️点击「阅读原文」

 免费报名 数据分析训练营

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/870661.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习 | 反向传播】释放反向传播的力量: 让训练神经网络变得简单

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

快速上手PyCharm指南

PyCharm简介 PyCharm是一种Python IDE&#xff08;Integrated Development Environment&#xff0c;集成开发环境&#xff09;&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如调试、语法高亮、项目管理、代码跳转、智能提示、自动…

为什么String要设计成不可变的

文章目录 一、前言二、缓存hashcode缓存 三、性能四、安全性五、线程安全 一、前言 为什么要将String设计为不可变的呢&#xff1f;这个问题一直困扰着许多人&#xff0c;甚至有人直接向Java的创始人James Gosling提问过。在一次采访中&#xff0c;当被问及何时应该使用不可变…

Axure RP9小白安装教程

第一步&#xff1a; 打开&#xff1a;Axure中文学习网 第二步&#xff1a; 鼠标移动软件下载&#xff0c;点击Axure RP 9下载既可 第三步&#xff1a; 注意&#xff1a;Axure RP 9 MAC正式版为苹果版本&#xff0c;Axure RP 9 WIN正式版为Windows版本 中文汉化包&#xff…

春秋云镜 CVE-2022-0410

春秋云镜 CVE-2022-0410 WordPress plugin The WP Visitor Statistics SQLI 靶标介绍 WordPress plugin The WP Visitor Statistics (Real Time Traffic) 5.6 之前存在SQL注入漏洞&#xff0c;该漏洞源于 refUrlDetails AJAX 不会清理和转义 id 参数。 登陆账户&#xff1a;u…

windows环境下打印机无法打印的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

js 使用 AES对字节数组进行加密

AES 分组密码算法和所有常见操作模式&#xff08;CBC、CFB、CTR、ECB 和 OFB。 js实现 aes 对字符串进行加密解密&#xff0c;网上有很多实现demo&#xff0c;但是对字节数组进行加密&#xff0c;找了很久都没找到合适的代码。我这次开发使用的场景是微信小程序直接解析ble协议…

力求超越ChatGPT,谷歌加入人工智能新项目

受到新贵OpenAI的威胁&#xff0c;谷歌承诺快速跟踪新的人工智能项目。 ChatGPT吓坏了谷歌。周五&#xff0c;纽约时报据报告的谷歌创始人拉里佩奇和谢尔盖布林与公司高管就OpenAI召开了几次紧急会议新聊天机器人谷歌认为这可能威胁到其价值1490亿美元的搜索业务。 由OpenAI创…

String为什么设计成不可变的?

为什么要把 String 设计成不可变的呢&#xff1f;有什么好处呢&#xff1f; 这个问题&#xff0c;困扰过很多人&#xff0c;甚至有人直接问过 Java 的创始人 James Gosling。 在一次采访中 James Gosling 被问到什么时候应该使用不可变变量&#xff0c;他给出的回答是&#xff…

服务器安全维护注意事项有哪些?

服务器的安全关系着公司整个网络以及所有数据的安全&#xff0c;我们该如何做好服务器后续的安全维护呢?河南亿恩科技股份有限公司&#xff0c;专注服务器托管23年&#xff0c;不仅是国内专业的互联网基础应用服务提供商之一&#xff0c;还是国家工信部认定的综合电信服务运营…

C语言 野指针

目录 一、野指针 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;野指针的分类 &#xff08;三&#xff09;指针未初始化 &#xff08;四&#xff09; 指针越界访问 &#xff08;五&#xff09;指针指向的空间释放 二、避免野指针 &#xff08;一&#xff0…

MATLAB图论合集(一)基本操作基础

本帖总结一些经典的图论问题&#xff0c;通过MATLAB如何计算答案。近期在复习考研&#xff0c;以此来巩固一下相关知识——虽然考研肯定不能用MATLAB代码哈哈&#xff0c;不过在实际应用中解决问题还是很不错的&#xff0c;比C易上手得多~ 图论中的图&#xff08;Graph&#xf…

【C/C++】用return返回一个函数

2023年8月13日&#xff0c;周日早上 我的第一篇使用了动态图的博客 #include<iostream> #include<windows.h>int loop(){int i0;while(1){Sleep(1000);std::cout<<i<<std::endl;}return 1; }int main(){std::cout<<"程序开始"<<…

【Bert101】最先进的 NLP 模型解释【01/4】

0 什么是伯特&#xff1f; BERT是来自【Bidirectional Encoder Representations from Transformers】变压器的双向编码器表示的缩写&#xff0c;是用于自然语言处理的机器学习&#xff08;ML&#xff09;模型。它由Google AI Language的研究人员于2018年开发&#xff0c;可作为…

【Bert101】变压器模型背后的复杂数学【02/4】

一、说明 众所周知&#xff0c;变压器架构是自然语言处理&#xff08;NLP&#xff09;领域的突破。它克服了 seq-to-seq 模型&#xff08;如 RNN 等&#xff09;无法捕获文本中的长期依赖性的局限性。变压器架构被证明是革命性架构&#xff08;如 BERT、GPT 和 T5 及其变体&…

Java经典OJ题 回文

OJ题 回文 1.题目2.判断范围是否合理2.1 普通代码2.2 优化代码 3.判断回文的关系代码4.总代码 1.题目 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字…

Multipass虚拟机设置局域网固定IP同时实现快速openshell的链接

本文只介绍在windows下实现的过程&#xff0c;Ubuntu采用22.04 安装multipass后&#xff0c;在卓面右下角Open shell 就可以链接默认实例Primary&#xff0c;当然如果你有多个虚拟机&#xff0c;可以针对不同内容单独建立终端的链接&#xff0c;而本文仅仅用Primary来说明。 …

孤儿进程与僵尸进程

进程退出 关于进程退出有两个函数 exit和 _exit&#xff1a;其主要差别是在于是否直接退出。 其流程主要区别如下&#xff1a; 孤儿进程&#xff08;不存在危害&#xff09; 父进程运行结束&#xff0c;但子进程还在运行&#xff08;未运行结束&#xff09;&#xff0c;这…

VS中.cu文件属性中项目类型没有cuda

问题 VS中.cu文件属性中项目类型没有cuda 解决办法 右键项目“自定义” ![请添加图片描述](https://img-blog.csdnimg.cn/9717093332604b5982e67b15108c9ec8.png 再回到cu文件右键属性就会出现cuda选项了 请添加图片描述