还是 sql 冲鸭... , 停不下来了都, 趁着激情还在, 赶紧再整一把, 也渐渐发现, sql 果然是非常强大的, 然后搞了半天, 发现在写sql 的时候, 从它执行顺序来思考, 这样反而会轻松很多哦.
表关系
需求 01
查询 每门课程 被选修的学生人数
分析
纯练练手而已, 毫无难度. 还是不断在强调关于 group by 的用法, 即, 用了 group by 后, select 的字段必须是在 group by 中 或者 是聚合函数. 不然则报错或引发歧义, 这个非常重要. 然后就是新手,比如像我这种, 分组筛选的. where 是在 group by 之前, having 是 group by 之后.
select
a.c_id,
b.c_name,
count(distinct a.s_id)
from score as a
inner join course as b
on a.c_id = b.c_id
group by a.c_id, b.c_name
+------+--------+------------------------+
| c_id | c_name | count(distinct a.s_id) |
+------+--------+------------------------+
| 0001 | 语文 | 2 |
| 0002 | 数学 | 3 |
| 0003 | 英语 | 3 |
+------+--------+------------------------+
3 rows in set (0.00 sec)
mysql>
需求 02
查询 只有两门课程的全部学生的学号和姓名.
分析
先按 s_id 分组, 然后分组过滤(having) 出 课程数量为 2 的学号, 再匹配下学生表即可.
-- 先看有哪些学号
select * from score
group by s_id
having count(distinct c_id) = 2
+------+------+-------+
| s_id | c_id | score |
+------+------+-------+
| 0002 | 0002 | 60 |
+------+------+-------+
1 row in set (0.00 sec)
然后再做一个子查询, 作为学生表的一个筛选条件.
select
s_id as 学号,
s_name as 姓名
from student where s_id in (
select s_id
from score
group by s_id
having count(distinct c_id) = 2
)
+--------+--------+
| 学号 | 姓名 |
+--------+--------+
| 0002 | 星落 |
+--------+--------+
1 row in set (0.01 sec)
拓展一波, 其实我现在, 反而是更加喜欢先多表连接的方式来弄, 这样对于更加复杂的逻辑, 也是能够处理的, 涉及的表都给它拼接起来, 要啥字段就拿啥字段, 随便玩..
select
b.s_id 学号,
b.s_name 姓名
from score as a
inner join student as b
on a.s_id = b.s_id
group by a.s_id
having count(distinct a.c_id) = 2
我发现自己, 在写 join 的时候, 常常忘了 写 on 的条件, 就瞎连接...真是无语了.
+--------+--------+
| 学号 | 姓名 |
+--------+--------+
| 0002 | 星落 |
+--------+--------+
1 row in set (0.00 sec)
今天的这两个, 都是练手题, 蛮简单的, 还是关键在于掌握着两种思路, 一种是 "子查询" 风格的, 有点像咱编程的 面向过程写法; 另外一种是 "Join" 风格的, 将相关的表,都给关联上, 然后再来慢慢优化, 就跟咱编程的 "面向对象" 有点像, 差不多这样吧. 然后我发现, 现在还是挺喜欢后者这种 join 的方式的, 都先给怼出来, 然后再优化. 具体看场景吧还是.
小结
- 从 sql 的执行顺序去写sql 会事半功倍, 兼顾 子查询 和 join 两种思维方式的结合
- group by , select 中只能放 与 group by 的字段 或聚合函数, where > group by > having
- join 的时候, on 理解为 True ... 如不写或 True 则是会全部连接起来..一定要写清楚 或者 多条件判断 结合 and 和 or