1. 联合查询
注:联合查询是面试中的重点,只要考到sql,大多数情况下都考的是联合查询,而且联合查询也是我们学习中的难点.
1.1 笛卡尔积
在实际开发中,数据往往来自不同的表,所以要多表联合查询.多表查询是对多张表的数据笛卡尔积.
它们是两张表的各行数据通过全排列得到的.
注意:关联表查询可以对关联表使用别名.
1.2 内连接
操作目的:查询许仙同学的成绩.
1.2.1 一般写法
连接步骤:
- 先确定要查询的信息都来自于哪些表.
- 针对这两个表进行笛卡尔积.
select * from student,score;
在上述结果中,我们发现表中有好多都是无效的数据.所以我们要加上一些连接条件(where限制条件)来去掉一些无效数据.连接条件一般用主键来连接. - 加上连接条件,去掉无效数据.
select * from student,score where student.id = score.student_id;
,使得学生表中的id与成绩表中的学生id对应.
- 再根据其他数据,补充其他限制条件,比如查询"许仙"同学的成绩.
select * from student,score where student.id = score.student_id and student.name='许仙';
- 把不必要的列去掉.
select student.id,student.name,score.score from student,score where student.id = score.student_id and student.name='许仙';
1.2.2 join写法
- 对两张表进行笛卡尔积.
select * from student join score;
- 加上连接条件.
select * from student join score on student.id = score.student_id;
- 指定其他条件.
select * from student join score on student.id = score.student_id and student.id=4;
4 去掉不必要的列.select student.id,student.name,score.score from student join score on student.id = score.student_id and student.id=4;
1.3 外连接
外连接分为左外连接和右外连接,如果联合查询,右面的表完全显示,我们说是右外连接,反之则是左外连接.与内连接不同的地方是对于空值/不存在的值,内连接是直接去掉,而外连接会将不保留的一列置为空.需要注意的一点是,外连接因为会涉及到左右的问题,所以只能用join写法来完成.
语法:
- 左外连接:select 字段名 from 表名1 left join 表名2 on 连接条件
- 右外连接:select 字段名 from 表名1 right join 表名2 on 连接条件
eg:select * from student left join score on student.id=score.student_id;
在这里我们可以看到,在成绩表中没有id为8同学的成绩,就是"老外学中文"的成绩,所以在外连接的联合查询中,我们直接把"老外学中文"的成绩置为空.我们再来对比一下内连接的结果:
可见在内连接的联合查询中,直接把"老外学中文"的成绩给去掉了.
其实在日常开发中,外连接比较常用,我们结合实际场景来考虑,如果说某个同学缺考,我们不可以把这个同学的名字直接除掉,我们就是应该把他的成绩置为空.
右外连接的原理相同,我们不再赘述.
下面我们通过一张图来形象的展示内连接和外连接的结果集:
1.4 自连接
自连接是指在同一张表中连接自身进行查询.就是把自己复制一份出来,自己和自己连接.但是这里需要注意的一点是,由于是表自己和自己连接,所以要给表起别名,否者分不清两张表那张是那张.
案例:
显示所有"计算机原理"比"Java"成绩高的同学.
-
select * from score as s1,score as s2 where s1.student_id = s2.student_id;
第一步,匹配学生id.
-
select * from score as s1,score as s2 where s1.student_id = s2.student_id and s1.course_id=3 and s2.course_id=1 and s1.score>s2.score;
把s1中的成绩筛选到只剩"计算机原理"的成绩,s2中的成绩筛选到只剩"Java"的成绩,之后再在最后加上限制条件,s1表的成绩大于s2表的成绩,就是"计算机原理"的成绩大于"Java"成绩的人.
自连接的作用其实在这里被体现的淋漓尽致:原本两门课的成绩在不同的行中,在这里通过自连接使得不同行中的数据到了不同的列中,列与列之间是可以直接进行比较的.
1.5 子查询
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询.
1.5.1 单行子查询
指的是子查询返回的结果集合是一行数据.
eg: 查询不想毕业的同班同学
select * from student where class_id=(select class_id from student where name='不想毕业');
当然也可以分为两步查询,首先查询不想毕业同学的class_id,之后再使用查询出的class_id去查询该班中有哪些同学.
1.5.2 多行子查询
指的是子查询的结果返回是多行数据,需要注意的是,由于返回的结果是一个不止有一个元素的集合,所以我们不可以在子查询中使用=,而是使用in关键字来判断查询的数据在不在子查询的集合中.
eg:查询语文或者英文的成绩.
select * from score where course_id in (select id from course where name='语文' or name='英文');
1.6 合并查询
在实际应用中,为了合并多个select的执行结果.可以使用union,union all. 使用union和union all时候,前后查询的结果集中,字段要一致.否者合不上.
- union
该操作用于取得两个结果集中的并集,在使用该操作符的时候,会自动去掉结果集中的重复行.
eg: 查询id小于3,或者名字为"英文"的课程.
select * from course where id<3 union select * from course where name='英文';
当然这句话也可以用or实现
select * from course where id<3 or name='英文';
既然使用or就可以实现,那么我们为什么偏要引入联合查询呢?答案是联合查询的结果可以来自不同的表,而or的结果只可以来自同一张表. - union all
该操作用于查询到两个结果集的并集,在使用该操作符的时候,不会去掉重复的元素.
select * from course where id<=6 union all select * from course where name='英文';
union和union all的区别只在是否去掉重复元素.