MySQL基础篇的补充

前言:

查询语句的书写顺序

select ===> from ===> where ===> group by ===> having ===> order by ===> limit

查询语句的执行顺序

from ===> where ===> group by ===> having ===> select ===> order by ===> limit

这个很重要,提前再复习一下。

这里如果有一些基础,但是语句不是很熟悉的同学,可以去看另一位大佬的博客:MySQL 有这一篇就够(呕心狂敲37k字,只为博君一点赞!!!)_mysql有这一篇幅就够了-CSDN博客

本篇在其基础上做了一些补充(作者抄了一遍大佬的博客,但还未经博主同意所以没有发布)。希望各位谅解。

一、分组查询:

在此之前我们先准备数据:

sql 复制代码
drop table if exists emp;

create table emp (
    id int primary key auto_increment,
    name varchar(20),
    role varchar(20),
    salary int
);

insert into emp values(null, '张三', '程序员',10000), (null, '李四', '程序员', 1100), (null, '王五', '程序员', 1200);

insert into emp values(null, '赵六', '产品经理', 9000), (null, '田七','产品经理', 9500),(null, '周八', '老板',100000);

此时我们直接进行分组查询:

sql 复制代码
select role, salary from emp group by role;

运行结果及分析:

所以分组查询往往还是要搭配聚合函数使用的,否则这里的查询结果就没有意义。

使用group by的时候,还可以搭配条件,需要区分清楚,该条件是分组之前的条件,还是分组之后的条件。

1. 搭配 where 使用

查询每个岗位的平均薪资,但排除张三

sql 复制代码
select role, avg(salary) from emp where name != '张三' group by role;

运行结果:

2. 搭配 having 使用

查询每个岗位的平均薪资,但是排除平均薪资超过2w的结果

sql 复制代码
select role, avg(salary) from emp group by role having avg(salary) > 20000;

运行结果:

二、联合查询(多表查询)

我们先准备数据:

sql 复制代码
drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;

create table classes (
    id int primary key auto_increment,
    name varchar(20),
    `desc` varchar(100)
);

create table student (
    id int primary key auto_increment,
    sn varchar(20),
    name varchar(20),
    qq_mail varchar(20),
    classes_id int
);

create table course (
    id int primary key auto_increment,
    name varchar(20)
);

create table score (
    score decimal(3,1),
    student_id int,
    course_id int
);

insert into classes(name, `desc`) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','xuanfeng@qq.com',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','xuxian@qq.com',1),
('00054','不想毕业',null,1),
('51234','好好说话','say@qq.com',2),
('83223','tellme',null,2),
('09527','老外学中文','foreigner@qq.com',2);
insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
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),
-- tellme
(80, 7, 2),(92, 7, 6);

此时要查询"许仙"的各科成绩:

我们先分析条件:"许仙"是学生表(student)中,而成绩是成绩表(score)中的,所以我们要联合这两张表,也就是将这两张表进行笛卡尔积;之后需要筛选条件,也就是学生表中的id对应成绩表中的id。

sql 复制代码
select * from student, score where id = student_id;

运行结果:

此时我们可以精简列,之后再加上学生表中姓名为"许仙"同学的条件即可。

sql 复制代码
select student.name, score.score from student, score where student.id = score.student_id and student.name = '许仙';

1. 基于多表查询和聚合查询的综合使用:

查询所有同学的总成绩及同学的个人信息:

sql 复制代码
# select * from student, score where student.id = score.student_id;
# select * from student, score where student.id = score.student_id group by student.name;


select student.name, sum(score.score) from student, score where student.id = score.student_id group by student.name;

运行结果:

2. 3张表的联合查询

列出每个同学的每门课程课程名字和分数:

这里会用到3张表,学生表、分数表、课程表。我们可以先利用两张表得到结果,之后再逐步筛选最终结果:

sql 复制代码
# select * from student, course, score where student.id = score.student_id;

# select * from student, course, score where student.id = score.student_id and score.course_id = course.id;

# select student.name, course.name, score.score from student, course, score where student.id = score.student_id and score.course_id = course.id;

# 此时列名含义模糊,我们可以起别名
 select student.id, student.name as student_name, course.name as course_name, score.score from student, course, score where student.id = score.student
_id and score.course_id = course.id;

运行结果:

三、内连接和外连接

上述操作都是内连接,对MySQL而言,进行多表查询还可以使用"外连接"。

如果这两个表里面的记录都是存在对应关系的,内连接和外连接的结果都是一致的;如果存在不对应关系,内连接和外连接就会出现差别。

此时我们先准备数据:

sql 复制代码
drop table if exists student;
drop table if exists score;

create table student (
    id int,
    name varchar(20)
);

create table score (
    id int,
    score int
);

insert into student values (1, '张三'), (2, '李四'), (3, '王五');

insert into score values (1, 90), (2, 80), (4, 70);

注意:此时两张表中的内容并没有一一对应,若一一对应使用内外连接结果都是一样的。

此时就可以发现student表中没有4号同学,而score表中没有3号同学成绩。

1. 内连接

和之前的多表查询一样:

查询学生和学生成绩:

sql 复制代码
select * from student, score where student.id = score.id;

运行结果:

2. 外连接

我们也是和内连接做相同操作,但是语法格式不一样:

sql 复制代码
select * from student join score on student.id = score.id;

# 以下方式与上述方式等价
select * from student inner join score on student.id = score.id;

# inner 可以省略

运行结果:

这就是外连接,join 代表逗号,where 换成 on,目前这两种写法等价。

2.1 左外连接

左外连接使用left表示:

sql 复制代码
select * from student left join score on student.id = score.id;

运行结果:

左外连接:以左侧表为基准,保证左侧表每个数据都会出现在最终结果中,若在右侧表中不存在,对应的列就会替换为null。

2.2 右外连接

右外连接使用right表示:

sql 复制代码
select * from student right join score on student.id = score.id;

运行结果:

右外连接:以右侧表为基准,保证右侧表每个数据都会出现在最终结果中,若在左侧表中不存在,对应的列就会替换为null。

2.3 总结外连接

如下图:

其实有全外连接,但是MySQL不支持。

四、自连接:

一张表,自己和自己进行笛卡尔积。

有的时候,我们需要进行 行和行 之间的比较,而sql只能进行 列和列 之间的比较。有的时候,可能会涉及到行和行比较的需求,就可以使用自连接,把 行关系 转换为 列关系。

数据准备:

sql 复制代码
drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;

create table classes (
    id int primary key auto_increment,
    name varchar(20),
    `desc` varchar(100)
);

create table student (
    id int primary key auto_increment,
    sn varchar(20),
    name varchar(20),
    qq_mail varchar(20),
    classes_id int
);

create table course (
    id int primary key auto_increment,
    name varchar(20)
);

create table score (
    score decimal(3,1),
    student_id int,
    course_id int
);

insert into classes(name, `desc`) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','xuanfeng@qq.com',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','xuxian@qq.com',1),
('00054','不想毕业',null,1),
('51234','好好说话','say@qq.com',2),
('83223','tellme',null,2),
('09527','老外学中文','foreigner@qq.com',2);
insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
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),
-- tellme
(80, 7, 2),(92, 7, 6);

显示所有"计算机原理"成绩比"Java"成绩高的同学成绩信息:

根据观察:也就是找课程3的成绩比课程1的成绩更高的同学信息(course id 3 比 course id 1 成绩高的同学)。

此时我们直接进行自连接:

sql 复制代码
select * from score, score;

运行结果:

可以发现报错,此时要起一个别名。

sql 复制代码
select * from score as s1, score as s2;

此时我们关注学生信息,所以可以确定筛选条件:

sql 复制代码
select * from score as s1, score as s2 where s1.student_id = s2.student_id;

运行结果:

此时就可以确定最终查询语句:

sql 复制代码
# 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;

# 最后精简一下列
select s1.student_id, s1.score as F3, s2.score as F1 from score as s1, score as s2 where s1.student_id = s2.stude
nt_id and s1.course_id = 3 and s2.course_id = 1 and s1.score > s2.score;

运行结果:

如果此时想要学生名字,就可以拿这个表和学生表做笛卡尔积;如果此时想要课程名字,就可以拿这个表和课程表做笛卡尔积。

五、子查询

这个在前面提到的文章讲到过,我们大概说一下,因为用处很小。

我们可以通过这两句SQL来完成,当然也可以通过合并SQL语句完成,也就是子查询。

1. 单行子查询

只返回一行查询记录。

查询与"不想毕业"同学的同班同学:

sql 复制代码
# 先利用第一个查询语句缩小范围
select classes_id from student where name = '不想毕业';

# 之后利用其结果确定最终结果
select name from student where classes_id = 1 and name != '不想毕业';

运行结果:

通过合并SQL语句来完成:

sql 复制代码
select name from student where classes_id = (select classes_id from student where name = '不想毕业') and name != '不想毕业';

2. 多行子查询

返回多行记录的子查询。尝尝搭配in使用。

查询"语文"或"英文"课程的成绩信息:

应该在course和score中进行查询,联合查询也是没有问题的。这里先展示联合查询:

sql 复制代码
select * from course, score where course.id = score.course_id and (course.name = '英文' or course.name = '语文');

运行结果:

分步查询步骤为:

1.先通过课程名字找到课程id

2.再通过课程id在分数表中进行查询

sql 复制代码
select id from course where name = '语文' or name = '英文';
select score.student_id, score.course_id, score.score from score where score.course_id in (4, 6);

运行结果:

子查询使用in关键字:

sql 复制代码
select score.student_id, score.course_id, score.score from score where score.course_id in (select id from course where name = '语文' or name = '英文');

运行结果:

六、合并查询(union关键字)

把多个sql查询结果集合合并到一起成为合并查询。这里我们主要了解union关键字。

查询id小于3,或者名字为"英文"的课程:

sql 复制代码
select * from course where id < 3 or name = '英文';

# 等价于

select * from course where id < 3 union select * from course where name = '英文';

运行结果:

union可以充当or的作用,但是union允许把两个不同的表合并在一起。

合并的两个sql结果集的列,需要匹配。

这里我们在准备其他的表:

sql 复制代码
drop table if exists score;

drop table if exists student;

create table student1(
    id int,
    name varchar(20)
);

create table student2(
    studentId int,
    studentName varchar(20)
);

insert into student1 values(1, '张三'), (2, '李四');

insert into student2 values(1, '张三'), (3, '王五');

查询两张表的学生信息:

sql 复制代码
select * from student1 union select * from student2;

运行结果:

可以发现:使用union进行合并的时候,是会对结果进行去重的,若不想去重,可以使用union all。

sql 复制代码
select * from student1 union all select * from student2;

运行结果:

总结:

查询语句的书写顺序

select ===> from ===> where ===> group by ===> having ===> order by ===> limit

查询语句的执行顺序

from ===> where ===> group by ===> having ===> select ===> order by ===> limit

重要的事情说三遍,虽然这些东西可能在实际上运用的很少,但是我们也必须了解,毕竟技多不压身。

相关推荐
凤枭香6 分钟前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
测试杂货铺13 分钟前
外包干了2年,快要废了。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
艾派森17 分钟前
大数据分析案例-基于随机森林算法的智能手机价格预测模型
人工智能·python·随机森林·机器学习·数据挖掘
小码的头发丝、43 分钟前
Django中ListView 和 DetailView类的区别
数据库·python·django
小兜全糖(xdqt)1 小时前
mysql数据同步到sql server
mysql·adb
Karoku0661 小时前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
周全全1 小时前
MySQL报错解决:The user specified as a definer (‘root‘@‘%‘) does not exist
android·数据库·mysql
Chef_Chen1 小时前
从0开始机器学习--Day17--神经网络反向传播作业
python·神经网络·机器学习
白云如幻2 小时前
MySQL的分组函数
数据库·mysql
千澜空2 小时前
celery在django项目中实现并发任务和定时任务
python·django·celery·定时任务·异步任务