目录
1.创建数据库 create database 数据库名;
2.查看所有数据库: show databases;
3.选中指定的数据库 use 数据库名;
4.删除数据库 drop database 数据库名;
1.创建表 create table 表名 (列明 类型,列名 类型,列名 类型....);
2.查看指定数据库下的所有表 show tables;
3.查看指定表的结构 desc 表名;
4.删除表 drop table 表名;
新增:insert into 表名 values(值,值,值...);
1.全列查询:查询表里的所有列 select * from 表名;
2.指定列查询:select 列名 from 表名;
3.查询列为表达式:select 表达式 from 表名;
4.给查询结果的列指定别名:select 表达式 as 别名 from 表名;
5.查询的时候,针对列来进行去重select distinct 列名 from 表名;
6.针对查询结果进行排序select 列名 from 表名 order by asc/desc;
7.条件查询:whereselect 列名 from 表名 where 条件;
修改:Update update 表名 set 列名 =值,列名 = 值...where 条件/order by/l imit;
删除:deletedelete from 表名 where 条件 /order by/limit;
MySQL是一个客户端 服务器结构的软件.我们在安装MySQL的时候,其实就已经把客户端和服务器安装好了.
服务器和客户端之间是通过网络来通信的.
主动发送数据的一方:客户端(client)
被动接受数据的一方:服务器(sever)
客户端给服务器发送的数据,称为"请求" request
服务器给客户端返回的数据,称为"响应" response
一个服务器是可以同时给多个客户端提供服务的(多个客户端可以同时给服务器发送请求,服务器进行对应的响应),也有特殊情况的存在,一个服务器只给特定的客户端提供服务(一般出现在分布式系统,各个结点之间的通信).
客户端和服务器,可以出现在同一个主机上,也可以在不同的主机上.
这里要注意的是:无论是不是同一个主机,客户端和服务器之间都是通过网络进行通信的,当服务器和客户端在一个主机上时,电脑即使不联网也不会影响数据库的使用,因为电脑上有一个特殊的环回网卡,可以让自己发送自己接收,不通过网线/wifi都可以进行通信.
客户端时和用户交互的部分,在客户端里,用户通过命令行输入sql语句.
服务器是存储数据的主体. 数据是存储在主机的硬盘上的.硬盘是计算机组成部分之一.
计算机组成部分:遵循冯诺依曼体系结构,包括:CPU,存储器,输入设备,输出设备.(计算机使用二进制来表示和存储数据)
存储器:包括内存和外存
内存:就是大家平时所说的内存
外存:硬盘,软盘,U盘,光盘
硬盘
内存和外存的区别:
- 内存上读写数据的速度快,外存的读写速度慢.(速度能差3~4个数量级,能够达到几千几万倍)
- 内存空间比较小,外存的空间比较大
- 内存比外存要贵
- 内存的数据是'易失'的,断电之后,数据就会丢,外存的数据是'持久'的,断电之后,数据还在
上图就是命令行客户端,是自带的客户端.除此之外还有图形化的客户端.
数据库存储的数据,要求存储空间要很大,能够持久化存储.
数据库是逻辑上用来存储数据的集合
在一个个数据表中,每一行是一条数据,称为是一条记录(record),一行里又有很多列,每一列称为一个字段(field).这就是一个关系型数据库,要求同一个表里的这些数据的列数和列的类型都是要匹配的.
数据库的操作:
1.创建数据库
看到OK这样的提示,说明创建成功了.0.00sec是执行的时间单位是秒,0.00不是不耗时间的意思,是时间小于10ms.
其中create,database都是SQL中的关键字(有特定含义的单词),关键字不区分大小写.
数据库的名字不能是SQL的关键字.
在创建数据库的时候,还可以指定数据库的字符集.
一般最常用的是utf8,mysql中的utf8不是真正的utf8.在utf8里无法表示emoji(表情),在mysql中可以表示,所以mysql搞了个utf8mb4(完全体utf8)
在计算机中,汉字占几个字节???
这取决于你当前使用的字符集,编码方式.
关于字符集/字符编码:
ascii
在计算机里表示英文字母,办法使用数字来表示字母,哪个数字表示哪个字母,具有对应的关系.
英文字母比较少,算上阿拉伯数字和标点符号,一个字节就够用了.
但是汉字就不一样了,常用的汉字有4千多个,加上生僻字大概一共有6w个左右,此时用一个字节表示就不够了.但是完全可以用两个字节来进行编码,两个字节表示的数据范围0~65535.
用一个大表格表示,在这个大表格里有两列,一列是汉字,一列是对应的数字
使用两个字节表示汉字的方式,最典型的就是GBK
windows简体中文版,默认的编码方式就是GBK
可以查询出任何一个汉字对应的编码数字.
Java里的内置的编码方式uninode,也是两个字节表示汉字的.
gbk虽然可以表示汉字,但是世界上不只汉字这一种文字,全世界有多种语言文字,这么多文字放到一起,很显然两个字节无法表示,就需要更多的字节来表示.
utf8:变长编码,长度是不固定的,对于汉字来说,utf8一般是3个字节.
它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部分修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。
当我们指定utf8后,会报错,是因为java106这个数据库我们刚才创建过了,报错的信息会提示我们数据库已存在.
该过名字后就不会报错了.
为了防止创建重复的数据库时会报错,我们可以用 if not exists,加上这个,意思就是如果存在就不创建了,不存在才真创建.
加上if not exists 之后就不会报错了,只是有个警告.
我们可以show warnings来查看警告信息.
错误和警告时有区别的:错误是严重的问题,遇到错误无法继续执行;警告是没有那么严重的问题,可以继续执行.
if not exists只是用来把错误变成警告的作用吗??
其实if not exists在实际工作中很有用.在工作中,由于执行的SQL语句很多,所以很多时候SQL是写到一个文件中,来进行批量执行,如果在执行过程中某个操作报错了,后续代码将无法继续执行.
2.查看所有数据库:
show databases;
注意databases是复数形式,不管你创建了几个数据库.
在这里可以看到除了我们创建的数据库外,还存在一些数据库,这些是系统的数据库.
->表示当前没有输入完,控制台里遇到;才是一个完整的sql,注意是英文分号
3.选中指定的数据库
一个mysql服务器上,数据库有多个,要进行操作,就需要确定是要针对哪个数据库进行操作的.
use 数据库名;
那么后续操作都是针对选中的数据库进行操作的.
4.删除数据库
drop database 数据库名;
删除数据库其实是非常危险的操作,这里没有回收站,一旦删除了,数据就没了.
关于数据库表的操作:
mysql的数据类型
要掌握数据库表的操作,先要掌握mysql的数据类型,数据库里的表,每一列都是带有类型的.
类型:整数,浮点数,字符串......
float/double单精度双精度浮点数,M表示有效数字的位数,D表示小数点后保留几位,并不适合保存精确的数据,内存模型就决定了无法精确表示数据,存在误差.
decimal可以精确的表示浮点数,牺牲了存储空间,牺牲了运算速度换来的是更精确的表示方式.
常用类型:int,double,decimal
varchar(size)是最常用的表示字符串的类型,带有一个参数,约定了存储的最大空间
varchar(128)表示这个列最多存128个字符(而不是字节,这里要区分)
根据实际需求,来决定设置多长合适(并不是这里写了128,就真的固定分配这么多内存,会动态适应,但是内存最大不会超过128个字符)
适合更长的字符串(很少见)
主要存储二进制数据
表的操作:
1.创建表
create table 表名 (列名 类型,列名 类型,列名 类型,列名 类型......);
要想进行表操作,务必先选中数据库(先use某个数据库名)
同一个数据库中,不能有两个表,名字相同.
表名和列名,不能和sql的关键字重复!!!
如果是在想用关键字命名,可以给表明/列明加上反引号引起来.
comment表示注释,这个注释只能在创建表的时候用,其他时候用不了.
-- 也可以来表示,-- 和//差不多,都是从这里开始到行末都是注释.两个减号加空格
2.查看指定数据库下的所有表
(前提是当前已经选中了数据库)
show tables;
3.查看指定表的结构.
desc 表名;
11表示显示的宽度(不影响存储)
4.删除表
drop table 表名;
操作数据库表的操作:
操作数据库最主要的操作就是:增删查改(CURD)
进行增删查改的时候,务必先选中数据库!!!!
C create 新增
U update 修改
R retrieve 查询
D delete 删除
新增:
SQL使用insert关键字来表示"新增"
insert into 表名 values(列,列,列.....);
每次新增,都是直接新增一行(一条记录)
values后面()中的内容,个数和类型要和表的结构相匹配!!
学生表里有两列,values()里的也得有两列,列数不匹配,会插入报错.
在SQL中,' '和" "都可以表示字符串.(SQL没有字符类型,只有字符串类型,其他的没有字符类型的编程语言,基本上也都是单引号和双引号都可以)
创建数据库的时候,可以手动指定字符集,如果没有显示指定,此时默认的字符集就是拉丁文,是不可以支持中文的.
创建数据库的时候,如果手动指定了字符集,就以手动指定的为准,如果没有手动指定,此时就会读取mysql的配置文件(my.ini),配置文件里面会写一个字符集,这个配置文件如果从来没有改过,默认情况下就是拉丁文.
当前建库时的字符集就是拉丁文.
insert除了可以插入完整的一行数据外,还可以指定列插入,此时未被指定的列,是以默认值来进行填充的.如果要指定多个列,要以英文逗号分隔
也可以一次指定插入多行记录,借助这个功能,就可以用一个sql插入多条数据.
因为在mysql中当前一次插入一条记录,分十次插入,效率要低于一次把10个记录一起插入~
原因:(1)由于网络请求和相应的时间开销引起的
(2)数据库服务器是把数据保存在硬盘上的
(3)mysql关系型数据库,每次进行一个sql操作,内部就会开启一个事务.每次开启事务也有一定 的开销.
查询:
select是sql中最复杂的操作,如果把插入/删除/修改的复杂程度比作1,查询的复杂程度可能就是几百.
1.全列查询:查询表里的所有列
select * from 表名;
*叫做通配符,代表了所有的列.
全列查询需要特别注意:现在进行select *无所谓,但是在实际工作中,不能随便在公司的生产环境上进行select *,这是一种非常危险的操作.因为公司的生产环境的服务器的数据库里存储的数据都是上TB级别的,进行全列查询就会把遍历所有的数据,把数据从硬盘上读出来通过网卡来进行发送.在数据量非常大的情况下,就容易把硬盘IO吃满或者把网络带宽吃满,那么,外面有很多用户要通过带宽来访问服务器,结果因为全列查询把带宽吃满了,就影响了用户的正常使用了.
2.指定列查询:
select 列名 from 表名;
通过指定列查询,相对于全列查询,结果会精简不少.
3.查询列为表达式:
在查询过程中,进行一个简单计算(列和列之间)
进行表达式查询的时候.查询结果会是一个"临时表",这个临时表并不是写入到硬盘中的,临时表的类型也不是和原始表的类型完全一致.(会尽可能把数据表示进去)
select只是查询,无论如何操作,都不会改变硬盘上的数据.
4.给查询结果的列指定别名
其中,as 可以省略(但是不建议省略,这样写更容易理解,也不容易出错)
5.查询的时候,针对列来进行去重
(把有重复的记录,给合并成一个)
也可以指定多个列,当指定多个列的时候,则是要求所有的列都相同,才算重复.
6.针对查询结果进行排序
order by 子句;
默认是升序(asc)
加上desc就是升序,desc是descend的缩写.
关于排序的注意事项:
(1).如果sql中没有显式的写order by,认为查询结果的顺序是不可预期的,写代码不能依赖自带的顺序.
(2).如果要排序的列中,有null,则null视为最小值.
(3).如果有多个记录,排序的列值是相同的,此时先后顺序也是不确定的.
(4).排序也可以根据表达式/别名 来进行,比如按照总成绩来排序
null和任何值进行计算,结果都是null
(5).排序还可以指定多个列来进行排序(更复杂的比较规则)
每一个列后面都可以加asc/desc来指定比较的规则
7.条件查询:where
根据查询的结果,按行进行筛选
通过where 指定一个条件,把查询到的每一行,都带入到条件中,看条件是真还是假,把条件为真的行保留下来(作为临时表的结果),条件为假的,舍弃.
要能够描述条件,现有一些关系运算符 和逻辑运算符
<=> 是针对NULL特殊处理了,使用=来比较某个值和null的相等关系结果仍然是null,null又会被当成false.
null和任何数据运算都是null,null<60结果还是null,当成了false,如果要带上null要加个条件
查询总分在200分以下的同学:
如果在条件里使用别名呢???
会识别不到.原因是:取决于mysql的内部实现,mysql在进行查询操作的时候,现针对每一行记录,计算条件,并按照条件进行筛选,满足条件的记录,才会取出对应的列,并且计算列里面的表达式(生成别名).
通俗一点讲就是where的执行发生在生成别名之前.
查询数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩:
查询姓孙同学的成绩:要用到模糊匹配
%可以表示任意个字符,'孙%'表示以孙开头的,'%孙'表示以孙结尾的,'%孙%'表示包含孙的无论开头还是结尾.
下划线_ 表示一个字符,'孙_'表示以孙开头并且孙后面有一个字符的.
模糊查询对于数据库来说,查询开销是比较大的.
修改:Update
update 表名 set 列名 = 值 where 条件;
把每一行都带入条件,条件为真的就要修改,为假就pass,可能是一次操作,修改多条记录.
这个修改操作,就是切实在改服务器的硬盘数据了,修改完之后,就会吃就生效.
修改操作也可以使用'表达式'来进行修改,可以把所有同学的语文成绩-5;
如果没写where子句,就是匹配所有行,但是有的语文成绩是空值,空值是没法进行算术运算的.
update还可以同时修改多个列,多个列之间用逗号分隔开.
update还可以搭配order by/limit 等子句来进行使用.
比如给成绩倒数四名的同学,数学成绩设置成10分
先加和得到总分,按照总分升序排序,去结果的前四个.
删除:delete
delete from 表名 where 条件;
比如要删除孙悟空同学的考试成绩:
删除操作也是在修改数据库服务器的硬盘,也是持久化删除,(删了就没了).
删除操作如果没写条件,就是把表里的所有记录都删除了.
数据库约束:
数据库约束是关系型数据库的一个重要功能,需要保证数据的完整性(正确的数据).
可以通过人工的方式来观察确认数据的正确性,但是不合适,这个事情就可能会导致人的疏忽,把一些错误没检查出来.
约束,就是让数据库帮助程序猿更好的检查数据是否正确.
约束类型:
1)not null
描述了是否允许是null,当加上not null之后,null这列,就变成了不允许为null.
当写入null,会报错.
2)unique
当id一列再次插入相同数据时,就会报重复的错误.
那么,数据库是如何判定,当前这一条记录时重复的???
先查找,再插入.加上约束之后,数据库的执行过程,可能就变了,很可能执行时间/效率受到很大影响.
但是这里的代价再大,也比人工检查一遍,代价小很多,而且准确率也高很多.
约束时可以组合在一起来使用的.一列可以同时加上多个约束(同时加上not null 和 unique)
PRI=>primary key,这样就引出了主键约束.
3)primary key
主键约束 就是 not null +unique
id这一列当插入null或者重复值的时候,就会报错.
主键也同样是在插入记录的时候,需要先查询,在进行真正的插入.
正因为主键 和 unique都有先查询的过程,mysql就会默认给primary key和unique 这样的列,自动添加索引,来提高查询的速度.
关于主键约束的注意点:
- 在实际开发中,大部分的表,一般都会带有一个主键,主键往往是一个整数表示的id.
- 在mysql中,只能有一个主键,不能有多个.
- 虽然主键不能有多个,但mysql允许把多个列放到一起共同作为一个主键(联合主键).
- 主键另外一个非常常用的用法,就是使用mysql自带的"自增主键"作为主键的值.(存在的意义:主键需要保证不重复,如果要是全靠程序猿自己生成一些不重复的主键值,就比较麻烦,而且容易出错)
自增主键:
在把id这一列设成自增主键后,插入id的时候可以手动指定,也可以不手动指定(null),则会由mysql自动生成!
插入null的时候不是说设成空值,而是交给数据库使用自增主键.
每次插入数据的时候,mysql就会自动找到上一条记录的id,在这个基础上,进行自增.
再插入一条记录,那么下一条是7还是101呢???
答案是101,自增主键,并不会利用中间的空隙,是依照之前的最大值,来往后累加的.这样做是最快的,要不然还要查找中间哪些id是空闲的.
4)default
5)foreign key:
外键约束,针对两个表之间,产生的约束.
classId 100 在class表中不存在,就认为是非法的数据.
为了让mysql帮我们自动的完成上述检查工作,就引入了"外键约束".
此处外键约束的含义,就是要求student里的classId务必要在class表的id列中存在!!!
1在class表中的id列中存在,可以插入成功.100在class表中的id列中不存在,所以插入失败.
学生表中的数据,要依赖班级表的数据,班级表的数据对学生表产生约束力(父亲对孩子有约束力)
故:此处起到约束作用的班级表,就叫做"父表"(parent);被约束的学生表,就叫做"子表"(child)
外键约束,表面上父表对子表有约束,实际上,子表也反过来约束了父表!!
当我们尝试删除id为1的class中的记录,发现删除失败!!
id为1,被子表给引用了,万一要删除成功,子表的数据就不合法了.
id为2,没有引用,可以删掉.
如果想要顺利删除,那就需要先删除子表,在删除父表.
在创建外键时需要注意的是:要想创建外键,就要求父表对应的列,得有primary key或者unique约束.
因为每次给子表插入数据,势必要在父表中查询一下,看看这个id是否存在.默认情况下查询是需要遍历表的,在表非常大的时候,遍历的效率非常低,所以要使用索引.
SQL中更复杂的查询:
将查询结果插入到另一个表中:
要求 查询结果 临时表的列数和列的类型,要和student2匹配.
聚合查询:
本质上是在针对行和行之间进行运算.
进行聚合查询,需要搭配,聚合函数.
1)count:
这个操作就相当于先进行select*,然后针对返回的结果,在进行count运算,求结果集合的行数.
不一定非要写*,也可以写成任意的列名/表达式.
现在插入一条全为空的数据.
在进行全列查询计数的时候,虽然有一行全为null,但还是会计算进去.
但是在进行名字的查询计数时,有一个name为空,计算count就给去掉了.
需要注意的是,count和()之间不能有空格,必须紧挨着!!
2)sum:
null和任何数据运算,结果都是null.sum会尽可能的避免这种情况.
需要注意的是:求和/平均值/最大/最小 这几个操作都是需要针对数字类型的列进行的.
3)avg:求平均值
不仅可以针对当前的某一列进行计算,还可以针对表达式进行聚合运算.
4)最大/最小:
求最大最小的时候,也会尽量避免null.
5)分组查询group by:
不使用group by分组的时候,相当于就只有一组,把所有的行进行聚合.
引入group by就可以针对不同的组,来进行聚合.
创建如图表:
如果要分组的话,我们一般是要根据岗位来分别统计,根据role这个类进行"分组".
如果不是带聚合查询的的普通查询,能否group by呢??
这里得到的就是每个分组的第一条记录(mysql里如果没有order by
,这里的顺序是不可预期的).
但是有的用户的mysql在进行不带聚合查询的group by时,可能会报下面的错误.
这是mysql的配置文件导致的,通过配置文件里面的一些选项可以来开关某些功能.
分组查询,也可以指定条件.
指定条件,有两种情况:
- 分组之前,指定条件. 先筛选,在分组. where
- 分组之后,指定条件. 先分组,在筛选. having
- 分组之前和之后,都指定条件.
分组之前,先指定条件:
统计每个岗位的平均薪资,但是刨除"孙悟空"的数据:
分组之后指定条件:
查询每个岗位的平均薪资,但是刨除平均薪资在1w之上的:
很明显,这个平均值,得是分组之后才能算出来,这个时候就需要先分组,在条件筛选.
分组之前之后都指定条件:
统计每个岗位的平均薪资,但是刨除"孙悟空"的数据,并且刨除董事长的平均薪资.
执行顺序:
联合查询:分表查询
多表查询的基本执行过程:笛卡尔积
创建如图的两个表:
进行笛卡尔积:from后跟表名,用逗号隔开
笛卡尔积是通过排列组合来的
列数是两个表列数之和.行数是两个表行数之积.
仔细观察,笛卡尔积里的结果很多是无效的数据,只有一部分是有意义的.
合法记录里,两个classId是想同的.所以可以通过添加条件来筛选合法的记录.
直接写classId = classId是会报错的,ambiguous是有歧义的意思.
.就是成员访问运算符,把表视为数据库的成员,列名可以视为是表的成员.加上条件之后,结果就只剩下"合法"数据了.
把用来筛选有效数据的条件,称为连接条件.
一组练习:需要先构造4个表出来.
student 学生
classes 班级
course 课程
score 分数
(1)查询"许仙"同学的成绩
先分析问题里涉及几个实体集:学生姓名在学生表里,成绩在分数表里.
因此要想完成上述查询,就需要把学生表和分数表进行联合查询.
如何具体进行联合查询???
1.先计算笛卡尔积
产生了160条记录. 根据我们前面的讨论,笛卡尔积其实产生了大量的无效数据.
2.引入连接条件
此处的连接条件里,不写表名也可以,因为当前的id和student_id是可以区分的,但是为了代码的可读性,还是把表名加上比较好.
3.再根据需求,加入必要的条件
4.把不必要的列去掉,保留想关注的列
联合查询,还有一种写法,使用join来完成.
或者还可以写作:
个人觉得还是from多个表好一点,这个写法更简单,更直观.但是from多个表,只能实现内连接.而join on 既可以实现内连接也可以实现外连接.
(2)查询所有同学的总成绩,及同学的姓名.
同学来自student表,总分来自分数表,此处是按照行的维度进行组织(要用到聚合查询).
a)先进行笛卡尔积
b)加上连接条件
c) 加上聚合查询.把同一个同学的行,合并到一个组里,同时进行计算总分.
(3)查询所有同学的成绩,及同学的个人信息.
结果查询表中,有个人信息(来自学生表)有课程名字(课程表),分数(分数表)
a)先进性笛卡尔积
b)引入连接条件,三张表,需要两个条件
c) 针对要求的列进行精简
使用join on 也可以进行三个表的查询
表1和表2先join,完成之后,在和表3 join
内连接和外连接:
内连接和外连接大多数情况下,没有什么区别.
比如要连接的两个表,里面的数据都是一一对应的,这个时候,没什么区别.
如果不是一一对应,就有区别了.
王五同学是没分数的,分数为70的同学,不知道是谁的.
此处的两张表不再是一一对应的.
上面两表的查询结果中,最终剩下的就是两个表里都有的数据,能够对应上的数据.
这两种写法,都是"内连接".如果使用"外连接",结果就不相同了.
左外连接 student left join score on
会把左表的结果尽量列出来,哪怕在右表中没有对应的记录,就使用null填充.
右外连接 student right join score on
会把右表的结果尽量列出来,哪怕咋左表中没有对应记录.就是用null填充.
自连接:
自己和自己进行笛卡尔积.
这个操作,不是一个通用的解决方案,而是特殊问题的特殊处理方法.
自连接的效果就是把行转成列.SQL中无法针对行和行之间,使用条件比较!!
但是有的需求里,有需要行和行进行比较,就可以使用自连接,把行转成列.
如:显示"计算机原理"比"java"成绩高的成绩信息.
这个题目就需要进行行与行的比较,所以用自连接.
这样写会报错,名字重复了,不是唯一的.
所以要起别名,起别名不仅仅可以针对列,还可以针对表名.起别名的时候as可以省略,但是不建议.
自连接排列组合也产生了大量的无效数据,也需要指定连接条件.
此处是需要每个同学自己的计算机原理和自己的Java比较,因此使用student_id来作为连接条件,保证每一行记录的所有列的信息都是针对同一个学生描述.
此处的结果是每个同学的的课程id进行了排列组合,需要把计算机原理和java筛选出来.
接下来就是要针对这三行里,看哪一行的计算机原理>java
子查询:
把多个sql组合成一个了.实际开发中,子查询,要慎用.
(子查询可能会构造出非常复杂,非常不好理解的sql,对于代码的可读性,很可能是毁灭性的打击,对于sql的执行效率,也很可能是毁灭性的打击.
单行子查询:返回一行记录的子查询.
如:查询与"不想毕业"同学的同班同学
(先去查询不想毕业的同学的班级id,再按照班级id来查哪些同学和他一个班)
子查询其实就是把下面两个表的操作合并:
合并:
()里的子查询必须只返回一条记录,()前面才能直接写=,否则是不行的.
把一个查询作为另一个查询的一部分条件(套娃).
多行子查询:返回多行记录的子查询
如:查询"语文"或"英文"课程的成绩信息:
1.先根据名字,查询出课程id
2.根据课程id查询出课程分数
分步查询:
多行子查询:
()里的查询结果是在内存中,如果查询结果太大了,内存放不下,in就用不了了,就可以使用exists代替.
(实际上更推荐的是直接多步完成查询就好,没必要强行合成一个了,exists本质上也就是让数据库执行很多个查询结果)
exists关键字,可读性比较差,执行效率也也大大低于in写法,使用这个是解决特殊场景.
合并查询:
合并查询本质上就是把两个查询的结果集合并成一个.(要求这两个结果集的列相同才能合并).
有人会有这样的疑问:直接用or不就行了,何必要用union???
用or,查询只能是来自同一个表.如果用union查询结果可以是来自于不同的表,只要 查询结果的列匹配即可.
列匹配:列的类型,列的个数,列的名字.
union all 和union 差不多,union是会进行去重的(把重复的行只保留一份)
union all可以保留多份,不去重.