关于MySQL操作详解

目录

数据库的操作:

1.创建数据库 create database 数据库名;

2.查看所有数据库: show databases;

3.选中指定的数据库 use 数据库名;

4.删除数据库  drop database 数据库名;

关于数据库表的操作:

mysql的数据类型 

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;

 数据库约束:

1)not null

2)unique

3)primary key 

4)default

5)foreign key

SQL中更复杂的查询:

聚合查询:

1)count

2)sum

3)avg:求平均值

4)最大/最小

5)分组查询group by

 联合查询:分表查询

内连接和外连接

自连接

子查询

 合并查询


MySQL是一个客户端 服务器结构的软件.我们在安装MySQL的时候,其实就已经把客户端和服务器安装好了.  

服务器和客户端之间是通过网络来通信的.

主动发送数据的一方:客户端(client)

被动接受数据的一方:服务器(sever)

客户端给服务器发送的数据,称为"请求" request

服务器给客户端返回的数据,称为"响应" response

一个服务器是可以同时给多个客户端提供服务的(多个客户端可以同时给服务器发送请求,服务器进行对应的响应),也有特殊情况的存在,一个服务器只给特定的客户端提供服务(一般出现在分布式系统,各个结点之间的通信).

客户端和服务器,可以出现在同一个主机上,也可以在不同的主机上.

这里要注意的是:无论是不是同一个主机,客户端和服务器之间都是通过网络进行通信的,当服务器和客户端在一个主机上时,电脑即使不联网也不会影响数据库的使用,因为电脑上有一个特殊的环回网卡,可以让自己发送自己接收,不通过网线/wifi都可以进行通信.

客户端时和用户交互的部分,在客户端里,用户通过命令行输入sql语句.

服务器是存储数据的主体. 数据是存储在主机的硬盘上的.硬盘是计算机组成部分之一.

计算机组成部分:遵循冯诺依曼体系结构,包括:CPU,存储器,输入设备,输出设备.(计算机使用二进制来表示和存储数据)

存储器:包括内存和外存

内存:就是大家平时所说的内存

 外存:硬盘,软盘,U盘,光盘

  硬盘

 内存和外存的区别:

  1. 内存上读写数据的速度快,外存的读写速度慢.(速度能差3~4个数量级,能够达到几千几万倍)
  2. 内存空间比较小,外存的空间比较大
  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 条件;

比如要删除孙悟空同学的考试成绩:

 删除操作也是在修改数据库服务器的硬盘,也是持久化删除,(删了就没了).

删除操作如果没写条件,就是把表里的所有记录都删除了.


 数据库约束:

数据库约束是关系型数据库的一个重要功能,需要保证数据的完整性(正确的数据).

可以通过人工的方式来观察确认数据的正确性,但是不合适,这个事情就可能会导致人的疏忽,把一些错误没检查出来.

约束,就是让数据库帮助程序猿更好的检查数据是否正确.


约束类型:

  NOT NULL - 指示某列不能存储 NULL 值。(允许null,选填项;不允许为null,必填项)
UNIQUE - 保证某列的每行必须有唯一的值。(表里存的数据,不能有重复的值)
  DEFAULT - 规定没有给列赋值时的默认值。  
PRIMARY KEY - NOT NULL UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标
识,有助于更容易更快速地找到表中的一个特定的记录。(非常重要的约束,每条记录的身份标识)
FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
CHECK - 保证列中的值符合指定的条件。对于 MySQL 数据库,对 CHECK子句进行分析,但是忽    略CHECK子句。(显式通过条件来描述字段的取值)(MySQL 5 不支持 check)   

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 这样的列,自动添加索引,来提高查询的速度.

关于主键约束的注意点:

  1. 在实际开发中,大部分的表,一般都会带有一个主键,主键往往是一个整数表示的id.
  2. 在mysql中,只能有一个主键,不能有多个.
  3. 虽然主键不能有多个,但mysql允许把多个列放到一起共同作为一个主键(联合主键).
  4. 主键另外一个非常常用的用法,就是使用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的配置文件导致的,通过配置文件里面的一些选项可以来开关某些功能.

 分组查询,也可以指定条件.

指定条件,有两种情况:

  1. 分组之前,指定条件.   先筛选,在分组.   where
  2. 分组之后,指定条件.   先分组,在筛选.    having
  3. 分组之前和之后,都指定条件.

 分组之前,先指定条件:

统计每个岗位的平均薪资,但是刨除"孙悟空"的数据: 

分组之后指定条件:

查询每个岗位的平均薪资,但是刨除平均薪资在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可以保留多份,不去重. 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值