【MySQL】一文搞懂MySQL语法(进阶)

前言

本文讲述了SQL语法一些进阶内容,全文3.4w字,都是一句一句话指导,相信用心看,肯定会有收获的,需要哪一部分的内容,点击目录即可跳转

这里是基础篇 先看这个在看本文效果更加好哦~:一文搞懂MySQL语法(基础篇)


一、数据库约束

约束是 关系型数据库的一个重要的机制,保证数据的“完整性”,比如考试成绩,小数 0-100之间 小数点后保存一位小数,进行了一个约束。

数据类型本身就能进行一部分数据校验工作

除此之外,约束也可以进行一部分数据校验工作

通过了这些数据的校验,就可以尽量避免出现一些“非法的数据”


  • List itemNOT NULL - 指示某列不能存储 NULL 值。
  • UNIQUE - 保证某列的每行必须有唯一的值。(比如身份证 电话号码这些)
  • DEFAULT - 规定没有给列赋值时的默认值。
  • PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标
    识,有助于更容易更快速地找到表中的一个特定的记录。
  • FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK - 保证列中的值符合指定的条件。对于MySQL数据库,对CHECK子句进行分析,但是忽略
    CHECK子句

1.2 NOT NULL约束

创建表时,可以指定某列不为空

一个数据库表,看bookname 现在是不允许为空 ,如果我们插入一个空就会出现错误
在这里插入图片描述
在这里插入图片描述
我们看一下这个表结构:不允许是空
在这里插入图片描述


1.3 UNIQUE:唯一约束

指定列为唯一的、不重复的: 比如身份证 电话号码

新表 unique

在这里插入图片描述

插入成功,在次插入 错误信息
在这里插入图片描述
表结构:
在这里插入图片描述

UNI :unique 标志

有unique的时候先查找 在插入,每次要先查 会有影响的效率,但是还是有必要的,因为数据更加可靠了


1.4 DEFAULT:默认值约束

指定id列为主键:新表 注意是 ’ '
在这里插入图片描述

表结构:
在这里插入图片描述

插入:
在这里插入图片描述
不指定 也会自己插入:
在这里插入图片描述


1.5 PRIMARY KEY:主键约束

primary key 表示了一个记录的身份标(相当唯一 && 不为空)

表:
在这里插入图片描述

表结构:可以看见null 也是不为空的
在这里插入图片描述
插入数据:主键为空 不允许!!在这里插入图片描述

插入数据:主键重复 不可以!!
在这里插入图片描述

主键同时具备了 not null 和 unique的效果

切忌不可以有2个主键:
在这里插入图片描述
重复错误
在这里插入图片描述
对于主键,要求不可以重复和为空,我们需要一个来关注它,当然肯定不可以是人来保证,出问题了怎么办。

在平时主键都是一个数值类型,比如 id (单纯的一个整数),我们可以使用mysql提供的“自增主键”来解决问题。

auto_increment:什么是自增主键呢? 就是比如你插入一个数据,id就自己变成1,在有一个数据,它就会增加一个变成2。

对于整数类型的主键,常配搭自增长auto_increment来使用。插入数据对应字段不给值时,使用最大值+1。

在这里插入图片描述

查看表结构:
在这里插入图片描述
插入数据:
在这里插入图片描述
这里可能大家有疑问 不是desc 看见id不可以是null吗,那么没有插入是不是null呢? 肯定是不是的,这里mysql自己生成了一个,而且id 还是 1,2,3,。。这样是自增,我们也可以在id 插入null,并不是插入null,也是给mysql自己生成。

自增主键不一定是自动的我们手动也是可以的:
在这里插入图片描述
那么我在插入一个自动的那么id是但是呢?
在这里插入图片描述

答案是:11
在这里插入图片描述


1.6 FOREIGN KEY:外键约束

外键涉及到了2张表

比如有一个学校 ,同学们自己有一个名字,还有一个班级

我们就会发现有2张表,学生表,和班级表

学生表有同学的名字和班级
(张三,101班 李四,102班)

班级表有班级信息
(101班 102班)


这个时候来了一个新同学 (王五,105班),可是大家发现 这个时候班级表中没有105班,那么还来一个105班是不是有点问题,有人说在加一个105班嘛,但是在此之前就有了105班 逻辑不符合了我们数据库并不是说数据符合要求了就可以了。

代码案列:

在这里插入图片描述

要注意学生表的id 要在班级表中存在过比如:
插入数据:班级表
在这里插入图片描述
插入学生表:李四在 101 班
在这里插入图片描述
如果把id变成 不是1 ,2 ,3 会怎么样呢? 就出现问题了 所以和上面的说法一样
在这里插入图片描述
如果给student插入的记录中,对于的classid在class 表中不存在就会失败。
在这里插入图片描述
这里引入了一个 child 和parent的解释:
student表:子表 被class约束
class表:父表 约束别人

补充:这里要求子表中设置foreign key 的时候,关联父表的列,需要带上primary key,或者 unique,要不然设不上去,在子表新增数据,会在父表当中触发查询,因此要注意这个小细节。


约束了子表 那么父表修改也会有影响,比我把刚刚的学生信息删除掉:

在这里插入图片描述
为什么呢??其实当前这个id为1的记录已经被引用了,如果一删除就非法了,这样的约束就把这2个表绑定在一起了。
在这里插入图片描述
有的场景我们确实要删除父表怎么办?比如 电商管理 商品表 和订单表 ,那么商品表如果我们有的商品要下架,那么怎么办呢?我们尝试删除这个商品,那么肯定删除不了,下面来看看合理的解决办法吧!

答:解决的思路是引入一个新的字段在商品表,通过这个字段表示记录有效还是无效,默认这个字段为1,表示有效,如果要删除商品 可以直接把字段变成0,此时这个就表示商品无效,这个时候并没有删除数据库的记录,(不会打破外键约束)同时标记无效状态,这个叫做 “逻辑删除


1.7 CHECK约束(了解)

MySQL使用时不报错,但忽略该约束:MYSQL 不支持该功能

在这里插入图片描述

可以在插入数据的时候检查是否是指定数据,目前mysql没有使用,不过其他的数据库会使用到还是不错的。


二、 表的设计

其实讲述设计这玩意挺不好说的,因为太抽象了,我们要搞明白它的反义词“具体”

其实我们数据库许多都是来着现实,比如一个学生表,里面有名字啊,年龄啊,性别啊,等等 这些都是来自我们的生活。例如 要想实现一个功能,发奖学金,此时需要姓名,学号,各科成绩即可。

具体怎么去设计表,表里有哪些字段,一定要和具体的需求,具体的问题场景密切相关,这些还是最简单的,我们有一种通用的设计手段:抓住实体和关系~找实体的过程就是面向对象编程一样,有点像
在这里插入图片描述
光是找到实体还不行,我们要理清楚它们之间的关系,怎么理清呢~~

学会造句:实体关系主要存在四种~ 下面三图是E R 图 矩形是实体 帮我们理清关系

  • 没有关系

  • 一对一关系
    在这里插入图片描述
    学生表和用户表可以放在有同感表中
    (学生id 姓名 ,用户名,密码)

  • 一对多关系
    在这里插入图片描述
    有2种设计模式:
    学生(学号,姓名)
    1 张三
    2 李四
    3 王五

班级表(班级id ,班级,学生id)
1 1班 1,2 张三李四在1班
2 2班 3 王五 在2班

不过一般不这样使用第一种有点像使用数组但是像mySQL这样的数据库,并不支持数组这样的类型,如果真的要这样表示,就需要把若干个id 整理成一个字符串,id之间使用,来分割,其他非关系型数据库,比如redis这种,是支持“数组”这样的类型
在这里插入图片描述
第二种设计模式
学生(学号,姓名,班级id)
1 张三 1 张三在1班
2 李四 1 李四在1班
3 王五 2 王五在2班

班级表(班级id ,班级名字)
1 1班
2 2班

这样的更加常见使用,我们更多使用这样的

  • 多对多关系
    在这里插入图片描述
    多对多关系我们需要第三张表来表示:

表结构

学生表(学号,姓名)
1 ---- 张三
2 ---- 李四
3 ---- 王五
课程表(课程id,课程名称)
1 ---- 语文
2 ---- 数学
3 ---- 英语
学生、课程表(学号,课程id)
1 ---- 1 ----->学号为1 的学生(张三) 选择了课程为1的课程(语文)
1 ---- 2 ----->学号为1 的学生(张三) 选择了课程为2的课程(数学)
2 ---- 2
3 -----2

站到学号的角度查询~ 查询学号等于1的课程id

1 1
1 2
张三选择了语文数学
在这里插入图片描述
站到课程的角度查询~ 查询课程id等于2的学生
2 2
数学被李四、王五选择


三、新增

插入查询结果 新增和查询操作结合在一起

语法:

insert into 表2 select * from 表1

比如我们新建 2 个表:
在这里插入图片描述
student1插入数据s2 没有插入
在这里插入图片描述
然后我们执行SQL语句:
在这里插入图片描述

最后结果:
在这里插入图片描述
此处需要保证,查询结果得到的列和前面的待插入的表的列要对应数据类型也要一样~

就是你第一个表是int 类型 和varchar类型 那么第二个表也要是一样的类型和列数量、

如果列不匹配就会出现这个问题:
在这里插入图片描述
那么怎么解决呢?使用以前的指定插入列就可以了
在这里插入图片描述


四、查询

4.1 聚合查询

4.1.1 聚合函数

常见的统计总数、计算平局值等操作,可以使用聚合函数来实现,常见的聚合函数有
在这里插入图片描述
聚合查询:把查询结果按照行的维度进行合并了(把很多行合并起来了)

聚合函数就像c语言的“库函数”一样~

案列:

  • COUNT 计算当前查询结果有多少行
  • – 统计班级共有多少同学
    SELECT COUNT(*) FROM eaxm_result;
    在这里插入图片描述
    这个也可以
    在这里插入图片描述
    我们要是在括号里面指定列
    在这里插入图片描述
    查询全部是8个指定列就是7个,因为这个null不算
    在这里插入图片描述

  • SUM 求和 必须针对数字类型的 数值类型的 如果是字符串 和日期不可以

统计数学成绩总分
在这里插入图片描述
不及格 < 60 的总分,没有结果,返回 NULL

在这里插入图片描述

如果我们硬要求和name就会出现警告
在这里插入图片描述

如果想查看警告怎么办呢?

使用show warnings

在这里插入图片描述

大概的意思是求和要转换为double类型出现问题


  • AVG
    统计平均总分
    在这里插入图片描述

  • MAX
    返回英语最高分
    在这里插入图片描述

  • MIN
    返回 > 70 分以上的数学最低分
    在这里插入图片描述

4.1.2 GROUP BY子句

group by 分组聚合~ (根据表里值分成多个组)

语法:

select column1, sum(column2), … from table group by column1,column3;

group by 后面指定一个列,针对这个列来说,值相同的记录就被归为一组了.
就可以使用上面的聚合函数来进行统计计算

初始数据有相同的值:
在这里插入图片描述

  • 查询每个角色的最高工资、最低工资和平均工资 通过role字段
    在这里插入图片描述

这里重复的值已经没有了被分组了,那么有人就会问那岂不是和distinct一样??

我们使用这个可以使用聚合函数来计算

我们可以这样看group by

在这里插入图片描述

每一个组一个平均值 最后的结果就是上面的那样,只有是聚合函数都可以添加.

分组聚合查询,是可以搭配一些条件来使用的~
可以针对分组之后的效果,再来进行条件筛选
此处的条件筛选,使用的是having字句,不是where

where 是分组之前进行筛选
having是在分组之后进行的

我们来看看题 查询所有平均工资>10000

在这里插入图片描述
题二:查询每个岗位的平均工资,但是去掉孙悟空

先看看没有去掉之前的
在这里插入图片描述
去掉之后的
在这里插入图片描述
select role ,avg(salary) from emp where name!=‘孙悟空’ group by role;

为什么要这样写,因为如果要去孙悟空,我们先group by 那么孙悟空就没有了 被分到组里面了,就不好去掉。

总结:
如果是分组之前的筛选条件,使用where ,写到 group by 的前面

如果是分组之后的筛选条件,使用having,写到 group by 的后面

一个SQL可以同时包括group by 和where

来看看这个sql语句的执行过程

select role ,avg(salary) from emp where name!=‘孙悟空’ group by role having avg(salary)> 1000 ;
在这里插入图片描述
第一步:遍历表,把所有name!='孙悟空’的条件筛选出来
第二步:按照role 来分变3个组
第三步:在分别计算每个组的avg
第四步:再根据having的条件,对最终结果来一遍筛选


4.2 联合查询

在联合查询中,包含一个核心概念,“笛卡尔积”

算法其实很简单 ,相当于把两张表的结果进行一个排列组合~

假设现在有两张张表,学生表,班级表

学生表(学号,姓名,班级id)
1 张三 1
2 李四 1
3 王五 2

班级表(班级id 班级名字)
1 1班
2 2班

笛卡尔积是针对两张表进行计算的~
先取出第一张表的第一行 ,然后依次和第二张表的被一行进行组合,得到的结果作为笛卡尔积中的记录
再取出第一张表的第二行,然后依次和第二张的每一行进行组合 依次类推

在这里插入图片描述
这个结果就是最终的 “笛卡尔积”,所有可能的结果都给搞出来了.

得到的结果任然是一个表,这个表的列数,就是两张表的列数之和。
这个表的行数,就是两张表的行数之积。

大家可能会想到,既然是相乘,如果两张表很大,最终得到的笛卡尔积是不是很大?
是的!! 所以大家要慎用!

其实我们观察这些结果,发现还是有许多地方不合理的,由于笛卡尔积,仅仅只是数学上的一个“排列组合”的计算,因此这里产生的结果就很多,它是把所有的可能性给列出来了,所以可能产生不科学的数据,下面来看一下不科学的数据(是否符合实际情况的)

在这里插入图片描述

张三的原始表是在一班,对应的也是一班所以是符合的。
在这里插入图片描述
下面这条是不符合的,张三并不在二班,
在这里插入图片描述
在接下来看 李四符合在一班
在这里插入图片描述
李四不符合在2班
在这里插入图片描述
王五不符合1 班,但是符合在2班在这里插入图片描述

大家可以发现,符合的条件,就是两张表都存在classid一样就是符合的!!这个就相当于多表查询的链接条件!!

多表联合查询就是基于笛卡尔积联合展开的~~

创建一个数据库,进行多表查询练习,student和classes之间是一对多关系,student和course之间是多对多的关系,score表表示student和course之间关系的中间表:
在这里插入图片描述
学生表结构:
.
班级表情况:classid建立联系
在这里插入图片描述
课程表:
在这里插入图片描述
分数表:studentid 关联到学生表,courseid 关连到课程表,这个就是之间表,多对多的关系

在这里插入图片描述

4.2.1 内连接

语法:

select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;

select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件


案例:
(1)查询“许仙”同学的 成绩

分析一下怎么写:“许仙”在student表里,成绩在score表,我们要结合这两个表,然后找到想要的结果,分散在两张表中,所以我们需要多表联合查询~针对两个表(进行笛卡尔积)

怎么进行笛卡尔积呢? 我们只需要 select * from 学生表,分数表在这里插入图片描述

我们怎么来看这个是不是笛卡尔积呢?

上面说过,笛卡尔积的列数,是两张表的列数之和

学生表5列,分数表3列那么是8列,这里正是8列
那么
笛卡尔积只是第一步,相当于排列组合得到了所有的可能,需要把其中一些无意义的数据给剔除掉,那么怎么剔除呢?

上面说到id相同的就是有意义的,那么在当前哪一列是有意义的呢?

在这里插入图片描述
我们需要这两个列id相匹配才保留下来,其他的不要了,我们只要在当前的笛卡尔积加上条件即可。

select * from student,score where student.id = score.student_id;
在这里插入图片描述
此处的写法只是在对比筛选,把符合条件的保留下来,不符合的干掉

在这里插入图片描述
为什么要student . id

当多表查询的时候,由于笛卡尔积中包含的列,来自于多个表,而且列名可能是碰巧一样的,此时通过表名.列名的方式来显示指出当前的列是哪一个表的列。

在java中就是 “成员访问操作符”,

在这里插入图片描述
执行之后记录少了许多!我们来看看对不对
在这里插入图片描述id全部符合条件,我们来看一下分别代表什么意思
在这里插入图片描述
在这里插入图片描述

看看这个 代表: 李逵同学id为1的课程,分数是70.5

这里4个数据分别的意思是:
在这里插入图片描述
课程id 为1的成绩是70.5
课程id 为3的成绩是98.5
课程id 为5的成绩是33.0
课程id 为6的成绩是98.0

这个结果的含义就是每个同学,每门课的成绩。

我们实际需要的是许仙的成绩,我们只要加一个条件按照名字来筛选。
在这里插入图片描述
当前是得到了所有的列,把列要简化一下,只留名字和课程名称,和课程分数。

在这里插入图片描述
最终结果就是这样的

多表查询/联合查询把所有的可能性通过笛卡儿积罗列出来,然后进行筛选,设定条件的时候,一般至少要指定一个连接条件(两个表之间要有一个带联系的id)

一定要重点理解笛卡儿积计算的过程,也要注意体会,“有效数据”,“无效数据”筛选,参与笛卡尔积的两张表不是毫不相关的,这个关联关系就是通过两张表公共的列来体现的~

三张表可以前2个表的笛卡尔积和第三个笛卡尔积结合,得到一个更加大的,正因为如此,我们觉得多表查询是一个效率比较低的操作,一般实际开发中,慎用多表查询,尤其不要把 2 ,3张大表进行多表查询~


多表联查还有其他的写法:我们一开始是select from 后面多个表名,使用逗号隔开,还可以通过 inner join on 这样的方式写多表查询,下面来我们看看:

在这里插入图片描述
先联合查询:
select * from student inner join score on student.id = score.student_id;
在这里插入图片描述简化一下列:select student.name,score.course_id,score.score from student inner join score on student.id = score.student_id and student.name=‘许仙’ ;
在这里插入图片描述当前的inner join 和select from 表名 表名一样的,这样大家使用哪一种都可以,不过我在这里还是推荐第一种简单明了,像后面的这样,其实还要考虑哪里写哪里,这样不太好。

不过既然第一种好,为什么还要有inner join呢?

多表联查的连接方式,不仅仅是内连接,还可以是左外连接和右外连接。使用到后面的这些必须使用join on来实现所以有存在的必要。

(2)查询所有同学的总成绩,及同学的个人信息
题解:总成绩,就是每个同学,所有的科目相加~

同学信息,在student表
成绩信息,在score表

此处就需要针对student和score联合查询

第一步:select * from student,score;

第二步:select * from student,score where student.id = score.student_id; 把没有用的数据给筛选

在这里插入图片描述
在这里可以看见,每个同学的,每门课程了·

我们要全部成绩相加,每个行和行相加我们需要使用聚合函数
在这里插入图片描述
需要按照学号分组,把同一个学号的成绩信息,分到同一个组中,在针对每个组,分别求和~~

第三步:select * from student,score where student.id = score.student_id group by student.id; 根据学生id来聚合分组
在这里插入图片描述
有没有发现这个数据是怎么来的?
在这里插入图片描述
其实是每一行同学的第一个数据:
在这里插入图片描述

所以我们不可以只使用group 因为只包含每组的第一条数据,多个成绩变成了一个成绩了,不过我们不关注,我们只关注总成绩
在这里插入图片描述

第四步:计算分组后的每一个的总分

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

在这里插入图片描述
总成绩就是分组之后,对每个组进行操作,有group by 每一组都去掉group by,没有的话就是一张表,就会计算所有的记录。 这个题目就是把聚合查询和联合查询在一起。

给表名起别名:别名 和表名之间使用空格分开,多个表名之间,通过 逗号隔开
在这里插入图片描述


(3)查询每个同学的每门课的成绩(这里每门带上课程名)

题解:通过题目可以发现,我们需要同学的名字(student表),成绩(score表),课程名(course表),所以是3张表联合了,不过写起来差不多。

第一步(笛卡儿积):select * from student , score,course;
在这里插入图片描述
第二步(筛选无效信息,加连接条件):select * from student,score,course where student.id = score.student_id;

先第一次筛选
在这里插入图片描述其实大家会发现数据还是不怎么完美为什么呢?因为这里还有联系,我们还得在连接一下。

在这里插入图片描述

大家可以看见4门课程就是李逵同学的成绩
在这里插入图片描述
第三步:对列精简
select student.name ,course.name,score.score from student,score,course where student.id = score.student_id and score.course_id = course.id;
在这里插入图片描述
这样就完成了!! 三表联合 2个这样连接条件,筛选就是我们的条件。

简单总结一下一般步骤:
1)先分析题目的信息来自那些表

2)把这些表进行笛卡尔积

3)再结合这些表之间的关联关系,指定连接条件,过滤掉不合理的数据

4)在补充上题目中的其他条件逐渐让最终结果,接近预期~

5)最后对查询的列进行精简

实际开发中,不建议写成这种很复杂的sql~
这种复杂的sql,执行效率,可读性,可维护性,都不太好~


4.2.2 外连接

外连接分为左外连接右外连接,其实外连接也是在对两个表做笛卡尔积,和内连接差不多,假设两个表里每一条数据是一一对应的,此时外连接和内连接就是等价的,但是有点时候可能存在一些没有对应关系,这个时候外连接就有差别了。

举个例子:
student表:
在这里插入图片描述
score表:
在这里插入图片描述可以发现学生表里的王五在score表中没有对应的id数据,

score表中的4,在学生表中没有对应的数据,这样的表就会产生区别,数据没有一一对应上

我们先来搞一个内连接:现在结果只包含两个记录,这两个记录在两张表中都有体现~~ 这个就是内连接的效果,它查出来的都是在两张表有联系的结果。

在这里插入图片描述
语法:

– 左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;

在刚刚join前面加一个left,发现左侧的这个表(student)数据是全的!王五在student里面是存在的,但是在score表里面没有对应的成绩,即使如此我们还是可以把结果放在连接结果之中,大不了把分数变成null。
在这里插入图片描述

语法:

– 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;

右连接,右侧的表格(score)表数据是全的! 我们可以发现右侧的分数id是全的,左边没有。
在这里插入图片描述


拿图表示:
在这里插入图片描述

如果联合查询,左侧的表完全显示我们就说是左外连接;

右侧的表完全显示我们就说是右外连接

那么我们会想能不能搞出去这样的全部显示出来:全外连接
在这里插入图片描述

类似于这样的结果:
在这里插入图片描述但是各位不好意思,mysql不支持这样的,全外连接就是把每个数据都查出来。


4.2.3 自连接

自连接是指在同一张表连接自身进行查询(笛卡尔积)

存在的最大意义就是:把行转换为列!!
查询时,我们指定的条件只可以让列和列之间比较~无法让行和行之间比较

比如查找xx同学语文大于英语的成绩,列于列之间容易比较。

像这样的表,要找出科目一大于科目二的同学,就不好找了
在这个表里面,不同科目的成绩是不同的行

在这里插入图片描述

案例:
显示所有“计算机原理”成绩比“Java”成绩高的成绩信息
题解:(找学生id)先找课程id 计算机原理 和java的id~

可以通过联合查询来完成,但是没有必要~ (我们实际开发中,像这样的场景大概率会先通过两个sql语句来分别查询 这2门课成绩,然后在带入到sql中完成具体 的查询)
在这里插入图片描述
看看哪一个同学的分数3 比 1高,现在要做的事情找出score表中哪一个同学的分数,课程1 小于课程3 的分数,我们使用自连接!

第一步:先自己和自己笛卡儿积,为了区别我们分别取别名
select * from score s1 , score s2;
在这里插入图片描述
第二步:筛选一下,仔细观察这里的计算机原理,和java的各自的分数出来了,因此我们的行转列已经出现了。
在这里插入图片描述

第三步:我们固定让s1表里面表示java,s2中表示计算机原理
在这里插入图片描述第四步:找java 小于计算机原理的(因为s1里面都是java,s2都是数据库原理所以比较没有问题)
在这里插入图片描述
第五步:精简列 这样就找到了!
在这里插入图片描述

这个自连接出场其实挺少的 但是每次出来都有意想不到的效果

光靠自己想其实不好想,还是结合这些案列

我们重点还是内连接为主。


4.2.4 子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

子查询,属于一种特别膈应的写法,典型的强行把多个sql合并成了一个~

  • 单行子查询:返回一行记录的子查询(第一次查询返回一条记录)

    查询与“不想毕业” 同学的同班同学:
    题解:不想毕业是一个同学的姓名 在student表里,要查找的结果还是姓名 classesid在student表也有:

第一步:先查找“不想毕业”的班级id
在这里插入图片描述

第二步:根据刚才的班级id再次查找出相同的班级id的同学
在这里插入图片描述
我们这里使用了2条sql,那么我们只使用一条sql语句怎么写呢?

怎么写呢? 谁先执行谁后写 把条件变成SQL语句,子查询只返回了一条记录

select name from student where classes_id =(select classes_id from student where name = ‘不想毕业’ );在这里插入图片描述


  • 多行子查询:返回多行记录的子查询

案例:查询“语文”或“英文”课程的成绩信息
题解:
第一步:先在course表中找课程id~

在这里插入图片描述

第二步:再根据课程id在score表里面查找成绩详情
在这里插入图片描述
子查询形式:
select * from score where course_id in (select id from course where name =‘语文’ or name = ‘英文’);
在这里插入图片描述
刚刚是使用in,现在我们可以使用exists,不过这个玩意用起来麻烦,还不好理解,还效率低! 但是可能会考。。。

select * from score where exists (select score.course_id from course where (name =’ 语文’ or name = ‘英文’)and course.id =score.course_id);

在这里插入图片描述
这种虽然查询的结果是一样的但是写法差异很大,而且执行过程也差别很大

第一种:

select * from score where course_id in (select id from course where name =‘语文’ or name = ‘英文’);

在这里插入图片描述
执行过程:
先执行子查询,查询结果放到内存里
再执行外层查询,根据刚才内存的结果,进行条件筛选~
一共执行2次SQL

第二种写法:

select * from score where exists (select score.course_id from course where (name =’ 语文’ or name = ‘英文’)and course.id =score.course_id);

在这里插入图片描述执行过程:
先执行外层查询~ 就会得到许多行记录~
针对每一行记录,带入到子查询中,什么意思呢
在这里插入图片描述每一行记录带入进去子查询(每获取到外层查询的一行,就都要执行一次子查询的SQL)
接下来如果子查询的结果集合为空,那么外层查询这一行记录就被忽略,如果子查询的结果集合非空,那么外层查询的这一行记录就被保留~

exists就是在检测这个子查询结果是否为空的集合~

因此第二次写法,相比第一次写法效果低很多~

那么这个就没有一点优点了吗? 我们上面说到第一个方法是查询的结果先放到内存里面,如果我们查询的结果很大怎么办?这个时候第一种写法就不可以了,但是第二种写法没有涉及到内存,全部是在磁盘上查,虽然会慢点,但是我们还是可以查的

总结:
第一种基于in查询的写法,速度是快,但是子查询如果集合很大,内存放不下,就凉了

第一种基于exists查询的写法,速度是慢,但是和内存关系不大,哪怕子查询很大,也可以保证执行出结果

子查询结果比较小,就优先使用第一种写法
子查询结果比较大,并且外层查询结果数量比较少,优先考虑第二种写法。

万一子查询的集合比较大,外层查询结果数量也很大… 那么建议不要使用数据库了 哈哈哈~~

在这里插入图片描述

记住这个区别就可以了,当做了解即可~


4.2.5 合并查询

合并查询: 把多个结果集合合并成为一个 ! 可以使用集合操作符 union,union all

  • union 当使用该操作符时,会自动去掉结果集中的重复行

    案例:查询id小于3,或者名字为“英文”的课程:

    直接使用or
    在这里插入图片描述
    使用union

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

    在这里插入图片描述

    union就是把2个结果合并 不过要注意它们的列要对应(类型和个数)


  • union all 当使用该操作符时,不会去掉结果集中的重复行。

    该操作符用于取得两个结果集的并集。用法差不多会一个就会另外一个

    那么为什么要有union 呢,其实还有些特点场景可以使用到,比如有2张表的数据
    all是针对这张表指定2条件

    union可以第一张表里面查,第二张表里面查,再合并,其实这些在面试中,或者工作中都不太常用。


好了写到差不多了,这些都是 进阶的一些SQL语法,想学好SQL还是得多敲

  • 42
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

意愿三七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值