MySQL笔记5
一、DML与DQL
1.DML
(1)概念
DML(Data Manipulation Language),聚焦表数据的增、删、改,是日常操作数据库内容的基础语法。
(2)新增数据(insert / replace )
insert语句:
给全部字段添加单条数据:insert into 表名 values (值1,值2……);
给指定字段添加单条数据:insert into 表名 (字段1,字段2……) values (值1,值2……);
批量添加多条数据:insert into 表名 values (值1, 值2, ...,值n), (值1, 值2, ...,值n);(全字段) insert into 表名 (字段名1, 字段名2) values (值1, 值2), (值1, 值2);(指定字段)
注:插入数据时,指定的字段顺序必须与值的顺序一致,字符串和日期型数据必须使用单引号或双引号定界。如果需要插入其他特殊字符,应该采用\转义字符做前缀
replace语句:
replace into 表名(字段列表) values (值列表);
replace into 目标表名(字段列表1) select (字段列表2) from 源表 where 条件表达式;
replace into 表名 set 字段1=值1, 字段2=值2;
与insert不同的是,使用replace语句向表插入新记录时,如果新记录的主键值或者唯一性约束的字段值与已有记录相同,则已有记录先被删除(注意:已有记录删除时也不能违背外键约束条件),然后再插入新记录;
注:使用replace的最大好处就是可以将delete和insert合二为一(效果相当于更新)
(3)修改数据(update)
update 表名 set 字段名1 = 值1 , 字段名2 = 值2 , .... where 条件 ;
注:where条件一般需要写上,否则会对所有行的对应字段进行更新修改
在生产环境中的数据库表,一般还有update_time字段,用于记录数据的更新时间的,所以一般修改某些字段时会同时修改update_time字段值为当前时间
(4)删除数据(delete / truncate )
delete语句(灵活删除,按条件删行,可回滚):delete from 表名 where 条件;
但删除数据后,可用 commit 提交事务,回滚将无效,相当于保存当前删除记录:
注: delele删除记录时,若无where字句则会清空表所有记录。delete 删除语句不能删除某一个字段的值,若需要删除某一个字段的值,可以使用update语句,将该字段值置为NULL即可。
truncate语句(暴力清空,快速删全表数据,不可回滚):truncate table 表名;
(5)drop、truncate、delete的区别
delete:删除数据,保留表结构,可以回滚,如果数据量大,很慢
truncate: 删除所有数据,保留表结构,不可以回滚,一次全部删除所有数据,速度相对很快
drop: 删除数据和表结构,删除速度最快
2.DQL
(1)作用
DQL(Data Query Language) :数据查询语言,使用SQL语句实现对数据表的查询
(2)语法组成
select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数
(3)子句执行顺序(从上往下)
子句 | 作用 |
---|---|
from | 指定查询的表 |
where | 指定行级过滤 |
group by | 分组 |
having | 分组过滤 |
select | 查询要返回的数据或表达式 |
distinct | 去重 |
order by | 返回数据时指定排序规则 |
limit | 指定返回数据的行数 |
(4)基本查询
select * from 表名;(查询所有内容)
select 字段1,字段2,字段3.....from 表名;(查询指定字段)
select 字段1 as '别名1' , 字段2 as '别名2' ... from 表名;(查询时给字段起别名)
注:as关键字可以对表或列进行重命名,使得SQL语句更加简洁易了,as可以省略。 别名中使用特殊字符,或者是强制大小写敏感、有空格时,都可以通过为别名添加引号实现
(5)去重查询(distinct)
select distinct 字段列表 from 表名(重复的的数据只选择一条)
(6)条件查询(where)
select distinct 字段列表 from 表名 where 条件列表;
算术运算符:加(+)、减(-)、乘(*)、除(/)和取模(%) 幂次方(**) ^
注:MySQL的+默认只有一个功能——加运算符,没有连接运算
dual表是一个虚拟表,用于测试或者在没有真实表的情况下执行一些查询操作,可以省略from dual
字符串123会转换为数值的123,非数值字符串进行数值运算会转为0:
NULL的写法必须为大写,不能加双引号:
注:空值是指不可用、未分配的值,不等于零或空格;
任意类型都可以支持空值,包括空值的任何算术表达式都等于空
字符串和null进行连接运算,得到也是null
条件运算符:(=、>、<、>=、<=、!=或<>)、BETWEEN...AND(在某个范围之内,含最小和最大值)、IN(...)(在in之后列表中的值,多选一)、LIKE(模糊匹配,_匹配单个字符,%匹配任意字符)
逻辑运算符:and或&&(多个条件同时成立)、or或||(任意一个成立)、not或!(非,不是)
<=>安全等于,可作为普通运算符的=,或等价于is NULL:
正则表达式作为条件(筛选id字段为9的学生记录):
(7)聚合函数(count、max、min、avg、sum)
select 聚合函数(字段列表) from 表名 null值不参与其运算
函数:count(统计数量)、max(最大值)、min(最小值)、avg(平均值)、sum(求和)
count(1)、count(*)、count(某字段)区别:
执行结果:
count(*)和count(1)——所有行进行统计,包括NULL行
count(某字段)——对某字段中非NULL进行统计
执行效率:
(1)如果列为主键,count(列名)效率优于count(1)
(2)如果列不为主键,count(1)效率优于count(列名)
(3)如果表中存在主键,count(主键列名)效率最优
(4)如果表中只有一列,则count(*)效率最优
(5)如果表有多列,且不存在主键,则count(1)效率优于count(*)
注:由于where子句是对逐条的行记录进行筛选,不是一组值,所以聚合函数不可用于where字句后面
(8)分组查询(group by)
select 字段,聚合函数 from 表名 [ where 条件 ] group by 字段 [ having 分组后过滤条件 ];
将数据指定列分组,常与聚合函数一起用
按照班级分组,使用round(对象,位数)函数进行小数控制,group by 按照分组字段进行归类,最后显示汇总信息:
查询平均分在90分及以上的班级:
查询每个班级的成绩平均分(不统计成绩在85分以下的学生,且过滤掉平均分在90分以下的班级),以便比较不同班级的成绩:
where和having的不同:
执行时机:
where是分组之前进行过滤,不满足where条件,不参与分组
而having是分组之后对结果进行过滤
判断条件:
where不能对聚合函数进行判断,而having可以
(9)排序查询(order by)
order by 字段1 asc/desc, 字段2 asc/desc.....
升序:asc(ascend),默认
降序:desc (descend)
排序依据为字符编码顺序排序,也可以自定义顺序排序
多次排序为分组排序,会在组内部进行再次排序
中文排序,由于使用字符编码不同会出现问题,如下按性别升序则女在前男在后了:
使用CONVERT函数按照指定编码排序:
先按性别排序,组内部按语文成绩降序排列:
在 MySQL 里,CAST() 和 CONVERT() 函数都能用于数据类型的转换
CAST(expression AS data_type)
expression:指的是要转换的表达式,它可以是列名、常量或者其他计算结果
data_type:表示目标数据类型,像 CHAR、DECIMAL、DATE 等
SELECT CAST(AVG(age) AS DECIMAL(10, 2)) FROM student;
CONVERT(expression, data_type;
expression:同样是要转换的表达式
data_type:目标数据类型
SELECT CONVERT(AVG(age), DECIMAL(10, 2)) FROM student;
CONVERT(expression USING character_set)
(10)分页查询(limit)
limit 初始位置,记录数 (从第几条记录开始显示,显示几条,第一条记录的位置是0)
limit 记录数(从第一条记录开始显示几条记录)
limit 记录数 offset 初始位置(从第几条记录开始显示之后的几条记录 ,偏移量方式)
用于限制查询结果的数量(常用于分页展示)
二、多表关联查询
1.多表之间的关系
一对一:一张表中的一条数据对应另外一张表中的一列数据,比如一个人只有一张身份证,一张身份证对应一个人。一对一关系比较少见,因为一对一这种关系的表可以合并成一张表
一对多:一张表中的一列可以和另外一张表中多条数据关联,拿学生表和成绩表举例,一个学生有多个成绩,
多对多:拿学生表和科目表举例,一个学生可以选择多门课程,一个课程也可以被很多学生选择;多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,将多对多的关系,拆成一对多的关系
2.交叉连接查询
select * from 表1,表2;
一张表的每一行去和另外一张表的任意一行进行匹配。笛卡尔积:即A表有m行数据,B表有n行数据,则返回m*n行数据。
先建好4张表
会发现有很多冗余数据:
查询所有学生信息以及课程名称课程课程对应的老师名称和学生成绩:
3.内连接查询
select 字段1,字段2... from 表1 inner join 表2 on 表1.字段=表2.字段 where 条件;
查询两个表的交叉部分,即共有字段
查询学生每门课的成绩及个人信息(仅显示有成绩的学生信息)和有条件的情况:
4.外连接查询
(1)左连接:select 字段 from 表1 left outer join 表2 on 表1.字段=表2.字段 where 条件;
以左边的表为主表,展示主表的所有数据,根据条件查询连接右边表的数据,若满足条件则展示,若不满足则以NULL显示(在内连接的基础上保证左边表的数据全部显示 )
查询学生每门课的成绩及个人信息(包括没有成绩的学生信息):
(2)右连接:select 字段 from 表1 right outer join 表2 on 表1.字段=表2.字段 where 条件;
右边的表为主表,展示右边表的所有数据,根据条件查询join左边表的数据,若满足则展示,若不满足则以NULL显示(在内连接的基础上保证右边表的数据全部显示 )
学生每门课的成绩及个人信息(不显示没有成绩的学生信息):
(3)联合查询:
又称为全外连接、满连接,用于将左表和右表的数据都查询出来,然后按照连接条件连接查询并去重(不去重)
union: 会自动压缩多个结果集合中的重复结果,对两个结果集进行并集操作,不包括重复行
union all: 则将所有的结果全部显示出来,不管是不是重复,包括重复行
注:
union 和 union all 内部的 select 语句必须拥有相同数量的列
每条 select`语句中列的顺序必须相同
查询循学生表和成绩表中有无成绩的所有学生信息,并且显示成绩表中有无学生编号的所有信息:
(不去重):
5.自连接查询
select 字段 from 表1 a , 表1 b where 条件;
select 字段 from 表1 a [left] join 表1 b on 条件;
自连接顾名思义就是自己跟自己连接,参与连接的表都是同一张表。(通过给表取别名虚拟出2张表)
查询每个学生的信息及班长姓名:
使用左连接查询城市归属的地区:
注:
自连接会增加查询的时间和空间复杂度,因此在实际应用中应谨慎使用
为了避免自连接造成的死循环,应该在where子句中加入限制条件,例如限制查询的层数
6.子查询
一个查询嵌套在另一个查询中,实现复杂条件过滤或数据聚合。子查询中可以包含:IN、NOT IN、some=ANY、ALL、EXISTS 和 NOT EXISTS等关键字,还可以包含比较运算符:= 、 !=、> 、<等
分类:
标量子查询: 子查询的结果是 (单行单列)
行子查询:子查询结果是一个数据(单行多列)
列子查询:子查询结果是一列(多行单列)
使用in运算符查询和孙德胜年龄相同的信息:
in运算符:外部查询的某个列的取值和查询结果中的任意一个数据相等即可
因表中有两个学生姓名为【孙德胜】,子查询查到两条记录。
则外部查询的条件为:只要年龄和其中的一个【孙德胜】的年龄相同即可
使用some和any运算符查询比孙德胜年龄大的学生信息:
ANY 和 SOME运算符 一般和大于号或小于号一起使用,SOME 和 ANY 的用法和查询结果完全相同
意义:表示比查询结果中的任意一个大(小)的即满足条件(比最小的大即可或比最大的小即可)
查询比孙德胜年龄小的学生信息:
使用all运算符查询比孙德胜年龄大的学生信息:
all运算符表示比查询结果中所有的数据都大(比最大的还大)或都小(比最小的还小)
查看学生表中是否存在sage信息(1为True,2为false):
添加测试数据后,查询学生表中学生所对应的班长以及班长能查询到对应名字的所有学生信息:
1是常量查询有数据显示按照数据行显示值,用来判断是否有数据
查看学生表中有对应的班长以及班长能查询到对应名字,并且学生年龄大于等于20岁的所有学生信息:
表子查询:子查询结果是一张临时表(多行多列)
查询LINUX和JAVA两门课的成绩信息:
7.子查询位置
select 后面:仅仅支持标量子查询(一行一列)
from 后面:支持表子查询(多行多列)
where 或having 后面:支持标量子查询(重要)\列子查询(一列多行)\行子查询(一行多列)
exists 后面(相关查询)
8.总结
子查询要包含在括号内,其查询结果可以当作数据源来用
列级子查询,需要用 in ,some\any ,all
表级子查询,返回结果不是当作条件用,而是当作表来用需要写在from 或 join后面