这一篇中,最重要的是对于复杂的SQL不一定要一步到位,最好一步一步来!!!
在数据设计时由于范式的要求,数据被拆分到多个表中,那么要查询⼀个条数据的完整信息,就要从多个表中获取数据,如下图所示:要获取学生的基本信息和班级信息就要从学生表和班级表中获取,这时就需要使用联合查询,这里的联合指的是多个表的组合。

参与查询的所有表取笛卡尔积,结果集在临时表中
笛卡尔乘积(Cartesian product)又称直积,是数学中两个集合X和Y的所有可能有序对组成的集合,表达式为X×Y,其中每个有序对的第一个元素来自X,第二个元素来自Y,具体的表达式为:A×B = {(x,y)|x∈A∧y∈B} ==>(1,1),(1,2)……(1,y) ==>(2,1),(2,2)……(2,y) ==>…… ==>(x,1),(x,2)……(x,y)

观察哪些记录是有效数据,根据两个表的关联关系过滤掉无效数据

如果联合查询表的个数越多,表中的数据量越大,临时表就会越大,所以根据实际情况确定联合查询表的个数
多表查询,尤其是笛卡尔积,是一个低效操作 实践中, 进行联合查询的时候,慎重,不要拿两个很大的表进行联合查询 即使是小的表,也不要一次性联合太多的表
#建课程表
create table course (
id int primary key auto_increment,
name varchar(50) not null unique
);
#建班级表
create table class(
id int primary key auto_increment,
name varchar(50) not null unique
);
#建学生表
create table student(
id int primary key auto_increment,
name varchar(50) not null,
sno varchar(20) not null,
age int,
gender tinyint,
enroll_date date,
class_id int,
foreign key (class_id) references class(id)
);
#建成绩表
CREATE TABLE score (
id INT PRIMARY KEY AUTO_INCREMENT,
score DECIMAL(5,1),
student_id INT,
course_id INT,
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
);
# 课程表
insert into course (name) values ('Java'), ('C++'), ('MySQL'), ('操作系统'), ('计算机⽹络'), ('数据结构');
# 班级表
insert into class(name) values ('Java001班'), ('C++001班'), ('前端001班');
# 学⽣表
insert into student (name, sno, age, gender, enroll_date, class_id) values
('唐三藏', '100001', 18, 1, '1986-09-01', 1),
('孙悟空', '100002', 18, 1, '1986-09-01', 1),
('猪悟能', '100003', 18, 1, '1986-09-01', 1),
('沙悟净', '100004', 18, 1, '1986-09-01', 1),
('宋江', '200001', 18, 1, '2000-09-01', 2),
('武松', '200002', 18, 1, '2000-09-01', 2),
('李逹', '200003', 18, 1, '2000-09-01', 2),
('不想毕业', '200004', 18, 1, '2000-09-01', 2);
# 成绩表
insert into score (score, student_id, course_id) values
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
(60, 2, 1),(59.5, 2, 5),
(33, 3, 1),(68, 3, 3),(99, 3, 5),
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
(81, 5, 1),(37, 5, 5),
(56, 6, 2),(43, 6, 4),(79, 6, 6),
(80, 7, 2),(92, 7, 6);查询学生姓名为孙悟空的详细信息,包括学生个人信息和班级信息
# 在from后同时写所有参与查询的表,并⽤逗号隔开
select * from student, class;
# 在where⼦句中加⼊连接条件
select * from student, class where student.class_id = class.id order by student.id;
# 依题意添加where条件
select * from student, class where student.class_id = class.id and name = '宋江';
由于两个表中都有 name 列,所以 MySQL 不清楚具体要使用哪个列,这时可以用“ 表名 . 列号 ” 的方式指定具体的列。
# 得到⽬标记录⾏
select * from student, class where student.class_id = class.id and student.name = '宋江';
select
student.id,
student.name,
student.sno,
student.age,
student.gender,
student.enroll_date,
class.name
from
student, class
where
student.class_id = class.id
and
student.name = '宋江';
select
s.id,
s.name,
s.sno,
s.age,
s.gender,
s.enroll_date,
c.name
from
student s , class c
where
s.class_id = c.id
and
s.name = '宋江';
select 字段 from 表1 别名1, 表2 别名2 where 连接条件 and 其他条件;
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 where 其他条件;(1)查询"唐三藏"同学的成绩
select s.name, sc.score from student s join score sc on sc.student_id = s.id where s.name = '唐三藏';
(2)查询所有同学的总成绩,及同学的个人信息
select s.name, sum(sc.score) from student s, score sc where sc.student_id = s.id group by (s.id);
Groupby使用了student.id进行分组,查询表列表中的student.name没有出现在Groupby分组 中,也没有包含在聚合函数中,这是因为SQL规定在Groupby分组查询时,如果查询列表中的列没有出现在GROUPBY子句中,但这些列的值在每个分组内部是相同的,那么它们可以出现在查询结果中。
(3)查询所有同学每门课的成绩,及同学的个人信息
select
s.id as id,
s.name as 姓名,
s.sno as 学号,
s.gender as 性别,
c.name as 班级,
sc.score as 分数
from
student s, course c, score sc
where
s.id = sc.student_id
and
c.id = sc.course_id
order by
s.id;
外连接分为左外连接、右外连接和全外连接三种类型,MySQL不支持全外连接。
左外连接:返回左表的所有记录和右表中匹配的记录。如果右表中没有匹配的记录,则结果集中对应字段会显示为NULL。
右外连接:与左外连接相反,返回右表的所有记录和左表中匹配的记录。如果左表中没有匹配的记录,则结果集中对应字段会显示为NULL。
全外连接:结合了左外连接和右外连接的特点,返回左右表中的所有记录。如果某⼀边表中没有匹配的记录,则结果集中对应字段会显示为NULL。

-- 左外连接,表1完全显⽰
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显⽰
select 字段 from 表名1 right join 表名2 on 连接条件;(1)查询没有参加考试的同学信息
# 左连接以JOIN左边的表为基准,左表显⽰全部记录,右表中没有匹配的记录⽤NULL填充
select s.id, s.name, s.sno, s.age, sc.* from student s LEFT JOIN score sc on sc.student_id = s.id;
# 过滤参加了考试的同学
select s.* from student s LEFT JOIN score sc on sc.student_id = s.id where sc.score is null;
(2)查询没有学生的班级
# 右连接以JOIN右边的表为基准,右表显⽰全部记录,左表中没有匹配的记录⽤NULL填充
select * from student s RIGHT JOIN class c on c.id = s.class_id;
# 过滤有学⽣的班级
select c.* from student s RIGHT JOIN class c on c.id = s.class_id where s.id is null;
由于内容较多,会分为多篇讲解,预知后续内容,请看后续博客!!!