#该题目来源于力扣:
1435. 制作会话柱状图 - 力扣(LeetCode)
一:题目要求:
表:Sessions
+---------------------+---------+
| Column Name | Type |
+---------------------+---------+
| session_id | int |
| duration | int |
+---------------------+---------+
session_id 是该表主键
duration 是用户访问应用的时间, 以秒为单位
你想知道用户在你的 app 上的访问时长情况。因此你决定统计访问时长区间分别为 "[0-5>","[5-10>","[10-15>" 和 "15 minutes or more" 的会话数量,并以此绘制柱状图。
写一个解决方案来报告 (bin, total) 。
返回结果 无顺序要求 。
结果格式如下所示。
示例 1:
输入:
Sessions 表:
+-------------+---------------+
| session_id | duration |
+-------------+---------------+
| 1 | 30 |
| 2 | 199 |
| 3 | 299 |
| 4 | 580 |
| 5 | 1000 |
+-------------+---------------+
输出:
+--------------+--------------+
| bin | total |
+--------------+--------------+
| [0-5> | 3 |
| [5-10> | 1 |
| [10-15> | 0 |
| 15 or more | 1 |
+--------------+--------------+
解释:
对于 session_id 1,2 和 3 ,它们的访问时间大于等于 0 分钟且小于 5 分钟。
对于 session_id 4,它的访问时间大于等于 5 分钟且小于 10 分钟。
没有会话的访问时间大于等于 10 分钟且小于 15 分钟。
对于 session_id 5, 它的访问时间大于等于 15 分钟。
二:思路流程
贸然进行判断会很麻烦,因为题中就给了一张表格,而需求却要返回一个经过聚合和判断的total和一个完全的新建列bin用来对total聚合列的判断。
要解决这个方法,可以自己用with函数新建两个数据框,第一个数据框是用casewhen判断函数组成的,用来判断原表格的duration属于哪个bin,第二个数据框是一个完全的新表,其中包括所有的判断项,将每一项用union函数进行连接。最后对自己的两个表格按照第二个数据框进行连接,然后按照bin进行分组,最后再进行聚合函数的判断即可。
第一步:
新建一个关于原表格的判断列,并且将其储存为一个名叫“b_bin”的数据框类型的变量:
WITH b_bin AS (
SELECT
CASE
WHEN duration < 300 THEN '[0-5>'
WHEN duration >= 300 AND duration < 600 THEN '[5-10>'
WHEN duration >= 600 AND duration < 900 THEN '[10-15>'
ELSE '15 or more'
END AS bin,
session_id,
duration
FROM Sessions
)
接着再创建第二张包含所有判断项的表格,储存为数据框形式的变量,命名为b_list:
WITH b_bin AS (
SELECT
CASE
WHEN duration < 300 THEN '[0-5>'
WHEN duration >= 300 AND duration < 600 THEN '[5-10>'
WHEN duration >= 600 AND duration < 900 THEN '[10-15>'
ELSE '15 or more'
END AS bin,
session_id,
duration
FROM Sessions
),
b_list as(
SELECT '[0-5>' AS bin
union
SELECT '[5-10>' AS bin
union
SELECT '[10-15>' AS bin
union
select '15 or mor
第二步:
检查这两张表,然后再思考下一步的数据分析:
b.bin为
| bin | session_id | duration |
| ---------- | ---------- | -------- |
| [0-5> | 1 | 30 |
| [0-5> | 2 | 199 |
| [0-5> | 3 | 299 |
| [5-10> | 4 | 580 |
| 15 or more | 5 | 1000 |
b.list为
| bin |
| ---------- |
| [0-5> |
| [5-10> |
| [10-15> |
| 15 or more |
现在要求,将b.bin表格中的数据,按照bin进行统计聚合,然后显示出来。
这样,复杂的问题就简化为了一个简单的分组聚合问题:按照b.list表的bin分组,然后统计出来分组后的b.bin的数量,最后返回b.list的bin和b.bin的count函数即可
第三步
对简单的分组聚合问题的实现:
先将两张表按照b.list(包含所有判断项的自建表)进行连接,然后进行分组聚合的判断即可:
select b_list.bin,ifnull(count(duration),0) as total
from b_list
left join
b_bin on b_bin.bin=b_list.bin
group by b_list.bin
三:最终代码演示
# Write your MySQL query statement below
WITH b_bin AS (
SELECT
CASE
WHEN duration < 300 THEN '[0-5>'
WHEN duration >= 300 AND duration < 600 THEN '[5-10>'
WHEN duration >= 600 AND duration < 900 THEN '[10-15>'
ELSE '15 or more'
END AS bin,
session_id,
duration
FROM Sessions
),
b_list as(
SELECT '[0-5>' AS bin
union
SELECT '[5-10>' AS bin
union
SELECT '[10-15>' AS bin
union
select '15 or more' as bin
)
select b_list.bin,ifnull(count(duration),0) as total
from b_list
left join
b_bin on b_bin.bin=b_list.bin
group by b_list.bin
解法二:
我们可以通过if函数外边套sum函数进行判断: if函数判断duration 是否符合条件,符合返回1,不符合返回0,然后用sum进行累加,就可以通过对原始数据的0/1转换再聚合,实现一个简单的条件统计:
# Write your MySQL query statement below
SELECT
'[0-5>' AS bin,
IFNULL(SUM(IF(duration < 300, 1, 0)), 0) AS total
FROM
Sessions;
/*可见第一个条件行已经被创建出来了
| bin | total |
| ----- | ----- |
| [0-5> | 3 |*/
如法炮制,船舰其他的判断语句,然后用union连接语句全部连起来就行,比较繁琐,但思路简单
# Write your MySQL query statement below
SELECT
'[0-5>' AS bin,
IFNULL(SUM(IF(duration < 300, 1, 0)), 0) AS total
FROM
Sessions
union
SELECT
'[5-10>' AS bin,
IFNULL(SUM(IF(300<=duration and duration<600,1,0)),0) AS total
FROM
Sessions
union
SELECT
'[10-15>' AS bin,
IFNULL(SUM(IF(600<=duration and duration<900,1,0)),0) AS total
FROM
Sessions
union
SELECT
'15 or more' AS bin,
IFNULL(SUM(IF(900<=duration,1,0)),0) AS total
FROM
Sessions
注意,再if判断函数里,不可以写成600<=duration<900类似的形式,会判断失误。要用if函数自带的连接函数and就像连接:600<=duration and duration<900