游戏行业实战案例 5 :玩家在线分布
【面试题】某游戏数据后台设有“登录日志”和“登出日志”两张表。
「登录日志」记录各玩家的登录时间和登录时的角色等级。
「登出日志」记录各玩家的登出时间和登出时的角色等级。
其中,「角色 id 」字段唯一识别玩家。
游戏开服前两天( 2022-08-13 至 2022-08-14 )的角色登录和登出日志如下
一天中,玩家可以多次登录登出游戏,请使用 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';
查询结果如下:
现在我们来计算各在线时间段的玩家人数,同样,使用 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 在线时间段;
查询结果如下:
可以看到,虽然我们已经得到了各在线时间段的玩家人数,但是在线时间段的排列是乱序的,查看分布情况不是很方便。因此,我们需要对在线时间段进行重新排序。
「在线时间段」这一列数据类型为字符串,无法用 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;
查询结果如下:
【本题考点】
1、考察逻辑分析能力,即:如何将复杂问题拆解成容易解决的一个个子问题的能力;
2、考察排序窗口函数的灵活使用。在需要进行分组排序时,排序窗口函数往往是首选;
3、考察 case when 语句的灵活应用以及分组汇总时,group by 子句、聚合函数的搭配使用;
4、考察纵向联结和横向联结的使用。纵向联结使用 union 方法(union、union all),横向联结使用 join 方法(left join、innerjoin、right join);
5、考察多重子查询的应用以及 with…as 语句的应用。
⬇️点击「阅读原文」
免费报名 数据分析训练营
相关文章:

游戏行业实战案例 5 :玩家在线分布
【面试题】某游戏数据后台设有“登录日志”和“登出日志”两张表。 「登录日志」记录各玩家的登录时间和登录时的角色等级。 「登出日志」记录各玩家的登出时间和登出时的角色等级。 其中,「角色 id 」字段唯一识别玩家。 游戏开服前两天( 2022-08-13 至…...

TypeScript 关于对【泛型】的定义使用解读
目录 概念导读泛型函数多个泛型参数泛型约束泛型别名泛型接口泛型类总结: 概念导读 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。使用泛型 可以复用类型…...

盛元广通食品药品检验检测实验室LIMS系统
随着食品与制药行业法规标准的日益提高和国家两化融合的不断推进,为保障检验工作的客观、公正及科学性,确保制药企业对于生产、实验室、物流、管理的信息化和智能化需求越来越明确,为确保新品可及时得到科学准确的检测检验结果,盛…...

【数据结构】-- 栈和队列
🐇 🔥博客主页: 云曦 📋系列专栏:数据结构 💨吾生也有涯,而知也无涯 💛 感谢大家👍点赞 😋关注📝评论 文章目录 前言一、栈📙1.1 栈…...

使用SpringAop切面编程通过Spel表达式实现Controller权限控制
目录 参考一、概念SpEL表达式 二、开发引入包定义注解定义切面定义用户上下文 三、测试新建Service在方法上注解新建Service在类上注解运行 参考 SpringBoot:SpEL让复杂权限控制变得很简单 一、概念 对于在Springboot中,利用自定义注解切面来实现接口…...

Flutter:简单搞一个内容高亮
内容高亮并不陌生,特别是在搜索内容页面,可以说四处可见,就拿掘金这个应用而言,针对某一个关键字,我们搜索之后,与关键字相同的内容,则会高亮展示,如下图所示: 如上的效果…...

2023/08/10
文章目录 一、计算属性传参二、小程序、h5跳转其他平台授权三、封装popup弹窗四、实现保存海报五、下载图片和复制分享链接 一、计算属性传参 计算属性的值往往通过一个回调函数返回,但是这个回调函数是无法传递参数的,要想实现计算属性传参可以通过闭包…...

LeetCode 1289. 下降路径最小和 II:通俗易懂地讲解O(n^2) + O(1)的做法
【LetMeFly】1289.下降路径最小和 II:通俗易懂地讲解O(n^2) O(1)的做法 力扣题目链接:https://leetcode.cn/problems/minimum-falling-path-sum-ii/ 给你一个 n x n 整数矩阵 arr ,请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下…...
Coin Change
一、题目 Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make changes with these coins for a given amount of money. For example, if we have 11 cents, then we can make changes with one 10-cent coin and one 1-c…...

2023 8 -14链表OJ
💕人面只今何处去,桃花依旧笑春风💕 作者:Mylvzi 文章主要内容:详解链表OJ题 题目一:环形链表(判断链表是否带环) 题目描述: 画图分析: 代码实现&#x…...
大数据必回之LSM树
LSM树(Log-Structured-Merge-Tree)并不像B、红黑树一样是一颗严格的树状数据结构,它其实是一种存储结构,像HBase、RocksDB这些NoSQL存储都是采用LSM树。它是一种分层、有序、面向磁盘的数据结构,核心思想是顺序写性能远…...
Vue中的Object.defineProperty详解
Vue中的Object.defineProperty是一个比较重要的方法,它是可以定义对象中属性的一个方法,相比于在对象中直接定义的对象,它更具有灵活性。 直接定义对象中的属性是这样的: let person {name:张三,address:广东,age:12,} 而Object.…...

MySQL高阶知识点(一)一条SQL【更新】语句是如何执行的
一条SQL【更新】语句是如何执行的 首先,可以确定的说,【查询】语句的那一套流程,【更新】语句也是同样会走一遍,与查询流程不一样的是, 更新语句涉及到【事务】,就必须保证事务的四大特性:ACID&…...
threejs实现模型gltf的动画效果
确保加载模型后模型有animations属性。加载完模型后,在模型中定义mixer的变量值。 // 4、加入加载器 const loader new GLTFLoader(); loader.load("./model/gltf/RobotExpressive/RobotExpressive.glb", function (gltf) {// 赋值动画给mixermixer ne…...

Harmony创建项目ohpm报错
Harmony创建FA模型的项目时报如下错: The registry is empty - edit .ohpmrc file or use "ohpm config set registry your_registry" command to set registry.解决方法: File -> Settings -> Build,Execution,Deployment -> Ohpm …...
44 | 酒店预订及取消的数据分析
1.背景介绍 数据集来自Kaggle网站上公开的Hotel booking demand项目 该数据集包含了一家城市酒店和一家度假酒店的预订信息,包括预订时间、入住时间、成人、儿童或婴儿数量、可用停车位数量等信息。 数据集容量约为12万32 本次数据分析主要包含如下内容: 总览数据,完成对…...

物联网和不断发展的ITSM
物联网将改变社会,整个技术行业关于对机器连接都通过嵌入式传感器、软件和收集和交换数据的电子设备每天都在更新中。Gartner 预测,全球将有4亿台互联设备投入使用。 无论企业采用物联网的速度如何,连接设备都将成为新常态,IT服务…...

加了ComponentScan,但是feign接口无法注入的原因
正文 正确的注入 如果发现无法注入:看看启动类Application是否有加入注解:EnableFeignClients(AppConstant.BASE_PACKAGES) 注意:EnableFeignClients和ComponentScan是两个独立的扫描,所以,如果只配置了ComponentSca…...
C#Winform中DataGridView控件显示行号实例
本文演示C#Winform中如何给DataGridView控件显示行号。 首先创建winform项目,添加DataGridView控件,给控件添加两列。 修改CS代码: using System.Windows.Forms;namespace DataGridviewDemo {public partial class Form1 : Form{public Form1(){InitializeComponent();//添…...

Stable Diffusion WebUI安装和使用教程(Windows)
目录 下载Stable Diffusion WebUI运行安装程序,双击webui.bat界面启动插件安装(github)模型下载(有些需要魔法)安装过程遇到的大坑总结参考的博客 整个过程坑巨多,我花了一个晚上的时间才全部搞定,本教程针对有编程基础…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...