通过对DQL的学习,我们可以很轻松的从一张数据表中查询出需要的数据;在企业的应用开发中,我们经常需要从多张表中查询数据(例如:我们查询学生信息的时候需要同时查询学生的班级信息),可以通过连接查询从多张数据表提取数据:
在MySQL中可以使用join实现多表的联合查询——连接查询,join按照其功能不同分为三个操作:
● inner join 内连接
● left join 左连接
● right join 右连接
数据准备
创建新的数据库db_test2
create database db_test2;
use db_test2;
创建班级信息表和学生信息表
create table classes(
class_id int primary key auto_increment,
class_name varchar(40) not null unique,
class_remark varchar(200)
);
create table students(
stu_num char(8) primary key,
stu_name varchar(20) not null,
stu_gender char(2) not null,
stu_age int not null,
cid int,
constraint FK_STUDENTS_CLASSES foreign key(cid) references
classes(class_id) ON UPDATE CASCADE ON DELETE CASCADE
);
添加数据
添加班级信息
# Java2204 包含三个学生信息
insert into classes(class_name,class_remark) values('Java2204','...');
# Java2205 包含两个学生信息
insert into classes(class_name,class_remark) values('Java2205','...');
# 以下两个班级在学生表中没有对应的学生信息
insert into classes(class_name,class_remark) values('Java2206','...');
insert into classes(class_name,class_remark) values('Python2205','...');
添加学生信息
# 以下三个学生信息 属于class_id=1的班级(Java2204)
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)
values('20220101','张三','男',20,1);
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)
values('20220102','李四','女',20,1);
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)
values('20220103','王五','男',20,1);
# 以下三个学生信息 属于class_id=2的班级(Java2205)
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)
values('20220104','赵柳','女',20,2);
insert into students(stu_num,stu_name,stu_gender,stu_age,cid)
values('20220105','孙七','男',20,2);
# 小红和小明没有设置班级信息
insert into students(stu_num,stu_name,stu_gender,stu_age)
values('20220106','小红','女',20);
insert into students(stu_num,stu_name,stu_gender,stu_age)
values('20220107','小明','男',20);
内连接 INNER JOIN
语法
select ... from tableName1 inner join tableName2 ON 匹配条件 [where 条件];
笛卡尔积
● 笛卡尔积(A集合&B集合):使用A中的每个记录依次关联B中每个记录,笛卡尔积的总数=A总数*B总数
● 如果直接执行select ... from tableName1 inner join tableName2;会获取两种数据表中的数据集合的笛卡尔积(依次使用tableName1表中的每一条记录去匹配tableName2的每条数据)
内连接条件
两张表使用inner join 连接查询之后生产的笛卡尔积数据中很多数据都是无意义的,我们如何消除无意义的数据呢?——添加两张进行连接查询时的条件
● 使用on设置两张表连接查询的匹配条件
-- 使用where设置过滤条件:先生成笛卡尔积再从笛卡尔积中过滤数据(效率很低)
select * from students INNER JOIN classes where students.cid = classes.class_id;
-- 使用ON设置连接查询条件:先判断连接条件是否成立,如果成立两张表的数据进行组合生成一条结果记录
select * from students INNER JOIN classes ON students.cid = classes.class_id;
● 结果:只获取两张表中匹配条件成立的数据,任何一张表在另一种表如果没有找到对应匹配则不会出现在查询结果中(例如:小红和小明没有对应的班级信息,Java2206和Python2206没有对应的学生)。
左连接 LEFT JOIN
需求:请查询出所有的学生信息,如果学生有对应的班级信息,则将对应的班级信息也查询出来
左连接:显示左表中的所有数据,如果在有右表中存在与左表记录满足匹配条件的数据,则进行匹配;如果右表中不存在匹配数据,则显示为Null
# 语法
select * from leftTable LEFT JOIN rightTable ON 匹配条件 [where条件];
-- 左连接:显示左表中的所有记录
select * from students LEFT JOIN classes ON students.cid = classes.class_id;
右连接 RIGHT JOIN
-- 右连接:显示右表中的所有记录
select * from students RIGHT JOIN classes ON students.cid = classes.class_id;
数据表别名
首先我们可以先将两张表stu_name和class_name字段名称都改为name
alter table students rename column stu_name to name;
alter table classes rename column class_name to name;
如果在连接查询的多张表中存在相同名字的字段,我们可以使用表名.字段名来进行区分
select students.name,classes.name
from students
INNER JOIN classes
ON students.cid = classes.class_id;
如果表名太长则不便于SQL语句的编写,我们可以使用数据表别名
使用示例:
select s.name,c.name
from students s
INNER JOIN classes c
ON s.cid = c.class_id;
子查询/嵌套查询
子查询—先进行一次查询,第一次查询的结果作为第二次查询的源/条件(第二次查询是基于第一次的查询结果来进行的)
子查询返回单个值-单行单列
案例1:查询班级名称为'Java2204'班级中的学生信息(只知道班级名称,而不知道班级ID)
● 传统的方式:
-- a.查询Java2204班的班级编号
select class_id from classes where class_name = 'Java2204';
-- b.查询此班级编号下的学生信息
select * from students where cid = 1;
● 子查询:
-- 如果子查询返回的结果是一个值(单列单行),条件可以直接使用关系运算符(= != ....)
select * from students where cid = (select class_id from classes where class_name='Java2205');
子查询返回多个值-多行单列
案例2:查询所有Java班级中的学生信息
● 传统的方式:
-- a.查询所有Java班的班级编号
select class_id from classes where class_name LIKE 'Java%';
+--------------+
| class_id |
+--------------+
| 1 |
| 2 |
| 3 |
+--------------+
-- b.查询这些班级编号中的学生信息(union将多个查询语句的结果整合在一起)
select * from students where cid = 1
UNION
select * from students where cid = 2
UNION
select * from students where cid = 3;
● 子查询
-- 如果子查询返回的结果是多个值(单行多列),条件使用IN / NOT IN
select * from students where cid IN (select class_id from classes where
class_name LIKE 'Java%');
子查询返回多个值-多行多列
案例3:查询cid=1的班级中性别为男的学生信息
-- 多条件查询:
select * from students where cid = 1 and stu_gender = '男';
-- 子查询:先查询cid=1班级中的所有学生信息,将这些信息作为一个整体虚拟表(多行多列)
-- 在基于这个虚拟表查询性别为男的学生信息(‘虚拟表’需要别名)
select * from (select * from students where cid = 1) t where t.stu_gender='男';