SQL 强化练习 (十一)
sql 冲冲冲....
也没啥可犹豫, 作为一名数据分析师, 必须掌握的技能, 就要熟练到写 Python 那样的感觉, 就应该可以了, 但目前还是差的比较远, 原因是, 没有相关的一些比较复杂一些的接触, 日常用的 sql 就相关简单, 字段筛选, 表连接, 分组聚合... 虽然都能写出来, 但总是不够自信的. 因此才经常从网上搬砖, 来练习 sql. 这一系列虽然都是关于咱最熟悉的 学生表, 选课表, 教师表 .. 之类的. 但真实业务中也是差不多的, 只是表变得更多和逻辑关系更复杂一些而已. 继续练习吧, 这种东西就是熟能生巧.
表关系
需求 01
查询不同老师, 所教不同课程平均分从高到低显示
分析
分别以, 课程, 老师的视角, 来处理平均分
首先呢, 先从 课程 的视角来做 group by , 看看不同课程的平均分.
select
sc.c_id,
c.c_name,
avg(sc.score) as avg_score
from score as sc
-- 课程名称
inner join course as c
on sc.c_id = c.c_id
group by sc.c_id
-- 降序
order by avg_score desc
+------+--------+-----------+
| c_id | c_name | avg_score |
+------+--------+-----------+
| 0003 | 英语 | 86.3333 |
| 0001 | 语文 | 80.0000 |
| 0002 | 数学 | 76.6667 |
+------+--------+-----------+
3 rows in set (0.00 sec)
蛮简单的, 即根据课程编号分组, 平均成绩做聚合, inner 上课程名称, 最后降序排列即可.
第二种理解, 是以 教师 来做 group by , 来求平均分.
select
t.t_id,
t.t_name,
avg(sc.score) as avg_score
from score as sc
inner join course as c
on sc.c_id = c.c_id
-- 再关联 teacher -> t_name
inner join teacher as t
on c.t_id = t.t_id
group by t.t_id, t.t_name
order by avg_score desc
+------+--------+-----------+
| t_id | t_name | avg_score |
+------+--------+-----------+
| 0003 | NULL | 86.3333 |
| 0002 | 仲尼 | 80.0000 |
| 0001 | 欧拉 | 76.6667 |
+------+--------+-----------+
3 rows in set (0.00 sec)
需求 02
使用分段 [100-85), [85-70), [70-60), [<60) 来统计各科成绩. 分别统计个分数段的人数, 课程id, 课程名称.
分析
先看看基本会涉及的 score 和 course 表, 关联起来
select
c.c_id,
c.c_name
from score as sc
inner join course as c
on sc.c_id = c.c_id
group by c.c_id, c.c_name
+------+--------+
| c_id | c_name |
+------+--------+
| 0001 | 语文 |
| 0002 | 数学 |
| 0003 | 英语 |
+------+--------+
3 rows in set (0.00 sec)
然后来进行分段统计啦, 要进行判断, 肯定是要用到 case when ... 来操作的.
select
c.c_id,
c.c_name,
-- 分组统计
sum(case when sc.score <= 100 and sc.score > 85 then 1 else 0 end) "100-85",
-- 计数用 count 更直观
count(case when sc.score <= 85 and sc.score > 70 then 1 else null end) "85-70",
sum(case when sc.score <= 70 and sc.score >= 60 then 1 else 0 end) "70-60",
count(case when sc.score < 60 then 1 else null end) "< 60"
from score as sc
inner join course as c
on sc.c_id = c.c_id
group by c.c_id, c.c_name
+------+--------+--------+-------+-------+------+
| c_id | c_name | 100-85 | 85-70 | 70-60 | < 60 |
+------+--------+--------+-------+-------+------+
| 0001 | 语文 | 0 | 2 | 0 | 0 |
| 0002 | 数学 | 1 | 1 | 1 | 0 |
| 0003 | 英语 | 1 | 2 | 0 | 0 |
+------+--------+--------+-------+-------+------+
3 rows in set (0.00 sec)
因此, 这里的技巧呢, 还是用了 case when 的用法, 外面再套一个聚合函数. 理解 sum 和 count 都能够实现这个 条件分组和统计的功能. 这个就看自己喜好了. 我个人还是喜欢用 sum 一点, 虽然 count 比较更直观, 这可能是跟我之前用 Tableau 的关系, 它默认的聚合字段就是 sum 嘛, 习惯了. 其实都行的.
也写了挺多的sql练习了, 总体的感觉是, 首先, 是要理清楚它需要哪些字段的参与, 以及多表关联的 key, 当不知道该怎么做的时候, 不妨将其拼接 join 起来, 再一步步查询; 然后就是理解 sql 的执行顺序, 先执行 from , 然后是 where, 在是 group by ... having .... 后面才到 select 因此, 我们在写 sql 的时候, 可以将自己当做 "机器" , 先写 from .. join ... where .. group by .. 最后才写 select , order by .. 这些. 这个思路非常关键,我觉得.
小结
- group by 要非常熟练使用, 就只要涉及聚合, 就要用, 注意 select 字段必须在 group by 中
- 条件求和, 用 case when .. 做一个标记值, 再在外面套一个 sum 或 count 都可以
- 根据 sql 执行顺序来写SQL,这样其实更能加深理解, from > where > group by > having > select ...