目录
在MySQL数据库中,表的操作是最重要的,表的操作分为对表结构的操作和对表数据的操作,前几期我们已经学习了对表结构的操作,本期我们将学习对表数据的操作。
表的增删查改
对表数据的操作无非就四种操作,增(create),删除(delete), 查(retrieve),改(update)。
增(create)
使用insert [into] 关键字进行数据的增加操作,我们一般称为数据的插入操作。
创建一张学生表。
单行数据,全列插入
多行数据,指定列插入
在前几期我们已经学习了主键和唯一键,对于主键和唯一键而言,这一字段的数据是唯一的不能重复,所以如果我们此时插入了重复的数据,就会报错。
为了防止报错的情况,引入了更新和替换的方案。
1.判断插入的数据与表原有的数据产生主键或者唯一键冲突,如果冲突就更新冲突的数据,如果不冲突就直接插入。
通过 duplicate key 关键字实现。
2.判断插入的数据是否与表原有的数据产生主键和唯一键冲突,如果冲突就删除原有的数据,然后插入新的数据,如果没有冲突,则直接插入。
通过 replace into 关键字实现。
两种方法的区别就是 duplicate key 同步时,如果插入的数据和原数据冲突,就更新原数据而并不删除,而 replace into 关键字替换时,如果与原数据冲突,就会先删除原数据,然后再进行插入,所以区别就在于对冲突数据的处理方法上。
通常我们说表中的一个数据就是一个记录,也就是表的一行内容。
查(retrieve)
通过select关键字进行查询。
创建成绩表exam_result,并且插入对应的数据。
全列查询
查询 exam_result 的所有字段的数据。
指定列查询
查询 exam_result name字段,chinese字段的所有数据。
表达式字段查询
将查询出来的 chinese字段 的值+10。
查询 name,chinese+math+english 字段,可以获得总成绩。
给字段起别名
查询 name,chinese+math+english 字段,给chinese+math+english起名为总分,可以获得总成绩。
查询 总分<200 分的学生的成绩。
此时我们惊奇的发现,mysql提示我们 总分 这个字段无法识别,这是为什么呢?
基于此,我们就要引入了sql语句执行顺序的概念,我们规定在sql语句的执行中,where子句是先于select子句执行的,所以就自然不能使用select中重命名之后的字段。
可以理解为是where子句先筛选数据,筛选完数据之后,此时select子句再去进行查询。
所以要实现上述情景,就不能使用重命名之后的字段,必须使用数据库表原有的字段。图示如下。
查询结果去重
使用distinct关键字可以对查询出来的数据进行去重。
通过exam_result 表发现 math 字段有重复的数据,所以我们对查询出来的math字段的数据进行去重。
以上我们查询出来的数据都是没有进行筛选过的数据,而数据库表中所有的数据,如果我们要对查询出来的数据进行约束,就要使用 where 条件。
where条件
比较运算符
运算符 | 说明 |
>, >=, <, <= | 大于,大于等于,小于,小于等于 |
= | 等于,NULL 不安全,例如 NULL = NULL 的结果是 NULL |
<=> | 等于,NULL 安全,例如 NULL NULL 的结果是 TRUE(1) |
!=, <> | 不等于 |
BETWEEN a0 AND a1 | 范围匹配,value属于[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1) |
IN (option, ...) | (option,...)括号中的可以理解为是一个集合 |
IS NULL | 是 NULL |
IS NOT NULL | 不是 NULL |
LIKE模糊匹配 | % 表示任意多个(包括 0 个)任意字符;_ 表示任意一个字符 |
逻辑运算符
运算符 | 说明 |
AND | 多个条件必须都为 TRUE(1),结果才是 TRUE(1) |
OR | 任意一个条件为 TRUE(1), 结果为 TRUE(1) |
NOT | 条件为 TRUE(1),结果为 FALSE(0) |
查询示例
查询英文成绩不及格(<60)的同学以及英语成绩。
查询语文成绩在[80,90]分的同学及语文成绩。
查询数学成绩是58或者59或者98或者99分的同学及数学成绩。
有两种方法,一种是使用or进行连接,一种是使用in条件。
查询姓孙的同学和孙某同学。
通过like进行模糊查询,%代表任意字符,_代表一个字符。
查询语文成绩好于英语成绩的同学及他们的英语成绩和语文成绩。
查询总分在200分以下的同学。
查询语文成绩 > 80 并且不姓孙的同学。
查询孙某同学,否则要求 总成绩>200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80。
查询 qq号为空 的学生,和 qq号不为空 的学生。
我们发现null是不能直接使用 = 进行判断的,必须使用 <=> 进行判断 ,一般情况下,判空的操作我们一般使用 is null 或者 is not null。
null 和 ' ' 的区别?
简单的来说 ' ' 代表有数据,数据是一个空串,而 null 代表没有数据。比如说学校的考试,小明去了教室考了零分,和小明缺考是不一样的,考了零分证明考了试,只不过成绩为0,缺考就证明没有考试。
查询结果排序
通常我们使用 order by 子句对于查询出来的数据进行排序,asc 排升序,desc 排降序。
查询同学的数学成绩,并对数学成绩升序排序。
查询同学qq号,并对qq号进行升序排序。
注意:null比任何值都小,所以排在最上面。
查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示。
我们发现此时查询出来的结果只有数学成绩符合查询出的要求,这是因为一张表中的数据,不可能同时满足上述的数学成绩降序,英语成绩升序,语文成绩升序。既然无法同时满足,那就满足第一个查询的要求,即数学成绩降序排序。
查询同学总分,并且由高到低显示。
此时,我们竟然发现,order by 子句中竟然又可以使用别名了,这是为什么呢?
这是因为,sql语句的执行顺序是不一样的,一般情况下,先是通过where子句筛选出符合条件的数据,然后对筛选出的数据进行select查询,然后对查询出来的数据进行order by排序,最终显示。所以order by子句是后于select子句执行的,所以当然可以使用select子句中设置的字段别名。
也正是因为where 和 order by子句的执行顺序是不一样的所以,这两个子句是可以同时出现的。
查询 姓孙 的同学或者 姓曹 的同学 数学成绩,结果按数学成绩由高到低显示 。
筛选分页结果
有时候我们可能会有只显示查询的数据的前几行的需求,所以此时就引入了筛选分页结果的概念。
通过limit关键字进行实现。
limit n :显示前n行。
limit s ,n:从s开始,显示n行。
limit n offset s:从s开始,显示n行。
改(update)
通常我们使用 update ... set 关键字进行数据的修改。
将孙悟空同学的数学成绩变为80分。
将曹孟德同学的数学成绩更改为 60 分,语文成绩更改为 70 分。
将总成绩倒数前三的3位同学的数学成绩加上30分。
要注意的是,update子句的执行顺序一定是在order by子句之后才执行的,可以理解为先通过order by子句将chinese+english+math字段查询了出来并且进行了排序然后最终保留了倒数前3的3个记录,最终由update子句进行数据更改。
将所有同学的语文成绩更改为原来的两倍。
如果没有where子句作为筛选条件,则最终更改的就是表中这一字段的所有数据,一般情况下我们不建议全表数据的更改,应该写上对应的where子句作为筛选的条件。
删(delete)
删除数据
使用 delete from 关键字进行数据的删除操作。
删除孙悟空同学的成绩。
删除整张表的数据。
新创建一个用于删除数据的表。
插入相应的数据。
删除整张表的数据。
往空表中再次插入一条数据。
我们发现,其实我们删除了整张表的数据之后,再次往空表中插入数据时,此时的主键依然是从4开始的,意味着自增并没有清零。
查看表结构,发现此时的主键id对应的auto_increment 字段显示为5,意味着下一条数据的主键从5开始自增。
截断表
简单来说,截断其实就是删除,通过 truncate 关键字对表进行截断的操作,需要注意的是,truncate只能对整张表的数据进行截断,也就是说只能删除整张表的数据,而不能删除一条数据。
创建要截断的表。
向表中插入数据。
删除所有数据,截断整张表。
向空表中插入一条数据。
我们发现此时插入的数据的自增长的主键值竟然变成了1。
查看表结构。
我们发现此时的自增长主键的值变成了2,意味着下一条数据的主键在没有设置的条件下会默认为2,也就意味着在使用truncate进行截断表时,自增的主键的自增值也会被清零。
综上,delete from 删除整张表和truncate 删除整张表的区别就是,delete from 不会清空表的自增主键的自增值,后续插入数据,数据的主键依然会按照上一条数据的主键的值进行自增;而 truncate 删除整张表时会重置表的自增主键的自增值,后续再进行数据插入时,自增主键的值又会从起始值1开始自增。
查询的结果作为数据插入其它表
select查询出来的数据,也可以作为源数据插入其它的表。
使用 insert into ... select... 实现。
要实现对表数据的去重操作,创建duplicate_table表,并插入数据。
查询duplicate_table的所有数据并对查询的数据进行去重,将去重之后的数据作为源数据插入新表,使用select distinct只是对查询的结果进行了去重,对表本身所存储的数据是没有去重的。
创建 no_duplicate_table为空表,可以使用 cteate table A like B;的sql语句创建A表,这样创建出来的表是一个与B表结构相同的空表。
将在 duplicate_table 中查询的不重复的数据作为源数据插入 no_duplicate_table 之中。
通过表的重命名实现表的数据的去重操作。no_duplicate_table表中是去重的数据,而duplicate_table中数据是没有去重的,所以先将duplicate_table重命名为old_duplicate_table,然后再将no_duplicate_table重命名为duplicate_table,此时就实现了原来的duplicate_table表中数据的去重。
聚合函数
函数 | 说明 |
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
查询统计操作
统计班级共有多少同学。
统计班级qq号有多少。
需要注意的是,null本身不计入个数的多少。
统计本次考试的数学成绩分数个数。
统计本次考试中不同的数学成绩的个数,简单来说就是对数学成绩去重之后数学成绩的个数。
统计数学成绩总分。
统计三门成绩的平均总分。
统计英语成绩最高分。
统计数学成绩>70分的最低数学成绩。
上述情景,得先通过where子句筛选出>70分的数学成绩,然后再通过select子句查询 筛选出来的>70分的所有数学成绩中最低的数学成绩。
group by子句
导入三个表,emp员工表,dept部门表,salgrade工资等级表。
显示每个部门的最高工资和平均工资。
做一个简单的分析,我们发现部门的编号和部门工资,这两个字段在emp表内,所以我们要先对emp表中的员工记录按照部门编号进行分组,一组代表一个部门,然后再对每组数据进行查询,就可以得到查询结果。
显示每个部门每种岗位的平均工资和最低工资。
做一个简单的分析,部门编号和岗位名称都在emp表里,所以首先对emp表进行查询,然后按照部门编号和岗位名称进行分组,一组就是一个部门的一个岗位所有员工的信息,然后依次对每组进行查询,就可以得到查询结果。
显示平均工资低于2000的部门和它的平均工资。
上述查询我们先使用group by对deptno进行了分组,每组就是一个部门的所有员工信息,然后select查询出了分组之后 每个部门的部门编号和平均工资,最终使用having子句对查询出的每组的结果进行筛选最终显示了最终的查询结果。
需要注意的是我们发现having子句中是可以用select中起的别名的,所以就可以得知having子句一定是后于select子句执行。
因为having子句后于select执行,而where子句先于select子句执行,所以就意味着where和having是可以同时存在的。
显示部门编号 >10 且平均工资大于 1000 的所有部门的部门编号和部门平均工资。
简单来说,where 和 having 都可以作为限制条件,不过where子句先于select执行,而having子句在select之后执行。
以上便是本期的基本查询相关的所有内容。
本期内容到此结束^_^