连接查询
1.基本概念
- 当查询结果来源多张表时,需要将多张表连接成一个大的数据集,再选择合适的结果返回。
- 连接查询可以通过连接运算符(连接条件)可以实现多个表查询。
- 内连接:查询的结果只显示两个表中满足连接条件的部分。
左连接:查询的结果为两个表匹配得到的数据,加左表特有的数据,对于右表中不存在的数据使用null填充。
右连接:查询的结果为两个匹配得到的数据,加右表特有的数据,对于左表中不存在的数据使用null填充。
2.内连接 inner join
2.1 标准语法
select * from 表1 inner join 表2 on 表1+匹配字段名 = 表2+匹配字段名;
- 创建表a和表b,并向其插入数据。
-- 如果表a存在则删除,不存在则不做任何操作 drop table if exists a; -- 创建表a create table a ( id int, name varchar(10) ); -- 向表a中插入数据 insert into a values(1,'张三'),(2,'李四'),(3,'王五'); select * from a; -- 如果表b存在则删除,不存在则不做任何操作 drop table if exists b; -- 创建表b create table b( id int, score int ); -- 向表b中插入数据 insert into b values(1,30),(1,40),(2,50),(2,60);
- 表a和表b数据展示。
表a和表b通过字段id内连接查询后的结果。
- select * from a inner join b on a.id = b.id;
- 查询结果列的说明:
- 表a和表b的列都会出现在查询结果中,由于表a和表b都有列名叫id 的字段,为了区分,表b 的id列显示为id1.
- 查询结果行的说明:
- 记录只保留表a 和表 b 中id字段相同的记录。
students表和scores表的数据说明
查询学生信息和学生的成绩,只显示有成绩的学生。
- select * from students inner join scores on students.studentNo = scores.studentNo;
- 查询结果只显示students 和scores两个表中studentNo相同的部分。
2.2隐式链接
select * from 表1,表2 where 表1.字段 = 表2.字段;
查询学生的信息和成绩,只显示有成绩的学生。
- select * from students,scores where students.studentNo = scores.studentNo;
2.3选择部分字段
查询学生信息,要求只显示姓名、课程、成绩。
- 标准语法:
- select name,courseNo,score from students inner join scores on students.studentNo = scores.studentNo;
- 隐式链接:
- select name,courseNo,score frmo where students.studentNo = scores.studentNo;
2.4表的别名
查询学生信息,要求只显示姓名、课程号、成绩,其中表students别名stu,表scores别名sc。
- select name,courseNo,score from students as stu inner join scores as sc on stu.studentNo = sc.studentNo;
— 练习
查询成绩表信息,同时显示成绩对应的课程表。
- select * from students inner join scores,courses on students.studentNo = scores,studentNo and scores.courseNo = courese.course.NO;
2.5带有wuere条件的内连接
- 语法格式
- select * from 表1 inner join 表2 on 表1.字段 = 表2.字段 where 条件;
查询王昭君的信息,要求只显示姓名,课程号,成绩。
- select name,courseNo,score from students inner join scores on students.studentNo = scores.studentNo where students.name = ‘王昭君’;
2.6带有and逻辑运算符的内连接查询
查询姓名为王昭君 并且成绩小于90的信息,要求只显示姓名,成绩。
- select name 姓名,score 成绩 from students
inner join scores on students.studentNo = scores.studentNo
where students.name = ‘王昭君’ and scores.score < 90;
2.7多表内连接查询
查询学生信息和成绩以及成绩对应的课程名称。
- select * from students
inner join scores on students.studentNo = scores.studentNo
inner join courses on scores.courseNo = courses.courseNo;
— 练习
写sql三步法:
- 搭建框架
- 基本的select语句框架搭建起来,如果有多表,把相应的多表也联合起来。
- 看条件
- 决定where后面的具体条件。
- 显示的字段
- select 后面到底要显示什么字段。
查询所有学生的Linux课程成绩,要求只显示姓名,成绩,课程名称。
- select name,score,coursename from students
inner join scores on students.studentNo = scores.studentNo
inner join courses on scores.courseNo = courses.courseNo
where courses.coursename = ‘Linux’;
2.8带有order by 排序的内连接查询
查询成绩最高的男生信息,要求只显示姓名,课程名,成绩。
- select name , coursename ,score from students
inner join scores on students.studentNo = scores.studentNo
inner join courses on scores.courseNo = courses.courseNo
where students.sex = ‘男’
order by scores.score desc
limit 1;
3.左连接 left join
- 语法格式
- select * from 表1
left join 表2 on 表1.字段 = 表2.字段;
- select * from 表1
查询所有学生的信息以及成绩,包括没有成绩的学生。
- students 表中有些学生在scores表中没有成绩;
- 左连接查询的结果为students和scores两个表匹配得到的数据,加上students表特有的数据,对于students表中不存在的数据使用null填充。
4.右连接 right join
- 语法格式
- select * from 表1
right join 表2 on 表1.字段 = 表1.字段;
- select * from 表1
查询所有课程的信息,包括没有成绩课程。
- courses表中courseNo为7的课程 python 在scores 表中没有对应的成绩;
- 右连接查询的结果为 scores 和courses 两个表匹配得到的数据,加courses表特有的数据,对于scores表中不存在的数据使用null填充。
- select * from scores right join courses on scores.courseNo = courses.couseNo;
注意事项
多表联合查询,重名字段的处理方式:
- 如果一条select 要用到多个表,且表中有同名字段,就需要表名.字段名 加以区分。
自关联
1.背景思考
- 设计省信息的表结构 provinces;
- proid:省略号;
- pname:省结构;
- 升级市信息的表结构 citys。
- cityid:市编号;
- cname:市名称;
- proid:市所属的省编号;
- citys表的 proid表示城市所属的省,对应着provinces表的proid值。
问题:
能不能将两个表合成一张表呢?
思考:
观察两张表发现,citys表 比 province表 多一个字段 proid,其它字段的类型都是一样的。
意义:
存储的都是地区信息,而且每种信息的数量有限,没必要增加一个新表,或者将来还要存储区,乡镇信息,都增加新表的开销太大。
答案:
定义表areas,结构如下:
- id
- name
- pid
表中的一条记录,可以记录省,也可以记录市。
- 记录为省的时候,字段说明:
- id:代表省
- name:代表省名称
- pid:因为省没有所属的省份,所以pid写为null。
- 记录为市的时候,字段说明:
- id:代表市id
- name:代表市名称
- pid:代表市所属省id
这就是自关联,表中的某一字段,关联了这个表中的另外一字段,但是它们的业务逻辑含义是不一样的,城市信息的pid引用的是省信息的id。
在这个表中,结构不变,以后还可以扩充区县,乡镇街道,村社区等信息。
1. 创建区域表areas,向表中插入数据
查询一共有多少个省。
- select count(*) from areas where pid is null;
查询广东省的所有城市
- select * from areas p inner
join areas c on p.id = c.pid
where p.name = ‘广东省’; - 子关联是同一张表作为连接查询。
- 子关联下,一定找到同一张表可关联的不同字段。
子查询
1.定义
- 在一个select 语句中,嵌入了另外一个select语句,那么被嵌入的select语句称之为子查询语句。
主查询
- 外层的第一条select语句为主查询。
主查询和子查询的关系
- 子查询是嵌入到主查询中。
- 子查询是辅助主查询的,要么充当条件,要么充当数据资源。
- 子查询是可以独立存在的语句,是一条完整的select 语句。
- 主查询离开子查询是不能独立运行的,依赖子查询的结果。
查询大于平均年龄的学生记录。
格式一
使用两条select语句实现。
- 第一步:查询平均年龄
- select avg(age) from students;
- 根据第一步的结果,查询大于平均年龄的学生记录。
- select * from students where age>30.1667;
格式二
用子查询实现。
- select * from students where age > (select avg(age) from students);
标量子查询:例如1格式中,子查询返回的结果只有一个值(一行一列),这种称为标量子查询。
查询30岁的学生的成绩
格式一:
使用两条select 语句实现。
- 查询30岁学生的学号
- select studentNo from students where age = 30;
- 根据学号查询成绩。
- select score from scores where studentNo in (‘001′,’003′,’011’);
格式二:
使用子查询实现。
- select score from scores where studentNo in (select studentNo from students where age = 30);
列子查询:比如例2格式二中,子查询返回的结果是一列(一列多行),这种称之为列子查询。
用子查询,查询所有女生的信息和成绩。
- select * from (select * from students where sex=’女’) as stu
inner join scores as sc
on stu.studentNo = sc.studentNo;
表级子查询:比如例3中,子查询返回的结果是多行多列(一个表),这种称之为表级子查询。