下午写完了上一篇文章,晚上就开始做牛客的SQL题啦,然后发现少少的十题就用到了好几次多表连接,case在实际分析过程中也非常常用,所以我打算单独把多表查询和case拉出来写一篇文章。
文章目录:
- 表的加法
- 表的联结
- 联结案例
- case表达式
一、表的加法
表与表相加最简单的方法就是使用union/union all这两个关键字,其中union会在求并集的时候去除完全一致的记录行,而union all则会保留所有的行。
例如:新建一个course1表,分别使用union/union all将其与原有course表合并
先看course1:

course:

union:

union all:

但是前文说的"重复",是只看主键,还是一行里所有的字段都看呢?
我将course1里 "0001 语文 0002"暂时改成了"0001 语 0002",执行同样的union语句:

注意事项:
- union(all)两侧的查询语句如果最终的输出列数量不一致,就会报错:

二、表的联结
为了降低数据库的冗余,使数据库好维护,也为了让相应的用户只看到自己该看的信息,我们在设计数据库时会尽量避免建立一个字段很庞杂的表。但实际使用的时候,我们往往需要结合多个表的信息一起看,这就要涉及到表的联结啦!

表的联结,往往是靠他们之间共有的列实现的:student(学号,姓名,性别),score(学号,课程号,成绩),这两个表就可以通过"学号"联结起来,查出同一个学生学习了哪些课程,成绩如何。
cross join(求笛卡尔积)由于使用频率不高,在此先略过。
①inner join 内连接:
运行示意图:

SQL示例:
select column1,column2,...column n
from table1 inner join table2
on table1.共有列=table2.共有列
where condition...;
②left join 左连接:
运行示意图:

SQL示例:
select column1,column2,...column n
from table1 left join table2
on table1.共有列=table2.共有列
where condition...;
但!是!想求出下图的红色块怎么办?

左连接由于保留了左表的所有记录,因此在右表做匹配时可能会存在没有值能和左表匹配上的情况。此时在联结出来的表中,有些记录的右表字段都是NULL。
NULL这一特征,就是我们破题的题眼→只要我们用where找出联结表中右表字段(多用的是左右两表的共有字段)为NULL的值,那么问题就解决了
SQL示例:
select * from table1 left join table2
on table1.sharedcolumn=table2.sharedcolumn
where table2.sharedcolumn IS NULL;→不要忘了判断是否为空用的关键字是 IS (NOT) NULL,而不是'=NULL'
③right join 右联结

SQL示例:
select column1,column2,...column n
from table1 right join table2
on table1.共有列=table2.共有列
where condition...;
和left join 一样的问题:怎么求出红色块

只要我们用where找出联结表中左表字段(多用的是左右两表的共有字段)为NULL的值,问题就解决了,具体SQL代码见上文。
注意:左右表联结由于只有一个表保留了所有记录行,因此有主次表之分。而主次表这样的情况在实际情况中非常常见,在此补充一个我做题时遇到的两个案例


③full join 全连接
MySQL不支持full join,所以在这里不多展开了。
三、联结实用案例
①求各学生的学号,姓名,选课数以及总成绩

②求平均成绩超过85的所有学生的学号,姓名,平均分

③求各个学生的学号,姓名,选修课程号,课程名称

四、case表达式
case表达式就像是中文中的固定搭配:如果...就..否则...,它可以实现许多复杂的判断条件。
SQL结构:
case(
when 列名 判断条件1 then 满足判断条件的操作1
when 列名 判断条件2 then 满足判断条件的操作2
...
ELSE 以上所有判断条件都不满足时对应的操作
END)
常用场景:
①做为查询结果中的一列,例如:
select 学号,(case 性别=‘F' '女' else ‘男' END) as 性别
from student;
②做聚合函数括号内的组成部分
sum(case avg(成绩)>60 then 1
else 0
END) as 及格人数
③做查询范围
④修改某列的值
update 学生
set 性别=
(case 性别='M' '男' else '女' end);
应用案例:查询每门课有多少学生及格,多少同学挂科
select 课程号,sum(case when 成绩>60 then 1 else 0 end) as 及格人数,count(*)-及格人数 as 不及格人数
from score
group by 课程号;
注意事项:case表达式中else可以省略,但end不行。