目录
一、Create:
单行插入:
多行插入:
插入否则更新:
插入否则替换:
二、Retrieve:
select查询:
全列查询:
指定列查询:
as重命名:
对查询结果去重:
where条件:
比较运算符:
逻辑运算符:
where语句使用案例:
查询结果进行排序(order by):
筛选分页结果
三、Update:
四、Delete:
删除表中数据:
截断表:
五、对表进行去重操作:
六、聚合函数:
七、分组查询:
having和where的区别:
什么是CRUD呢?
CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除)
一、Create:
首先,我们创建一张学生表,然后进行测试
mysql> create table student(-> id int unsigned primary key auto_increment,-> name varchar(20),-> QQ int unsigned unique,-> sex enum('男','女')-> );
单行插入:
单行插入在前面章节我们已经使用过很多次了,这里做下总结:
insert into 表名称(列属性, 不添加默认为全列插入) values (数据);
多行插入:
如果想插入多行,像上面那样一行一行插入比较麻烦,可以在values的后面进行逗号分割开()即可
插入否则更新:
如上,我们的表中是存在主键和唯一键的,所以在插入的时候,如果冲突了就会插入失败
主键冲突:
唯一键冲突:
我们可以在最后加上:
on duplicate key update XX=XXX ...;
其意思就是,首先插入,如果发现插入失败,就更新数据为后面的
- 0 row affected: 表中有冲突数据,但冲突数据的值和 update 的值相等
- 1 row affected: 表中没有冲突数据,数据被插入
- 2 row affected: 表中有冲突数据,并且数据已经被更新
可以使用库函数来进行查看上一次影响了多少行
插入否则替换:
除了insert可以插入数据,还有replace也可以插入数据,replace与insert不同的是
- 主键 或者 唯一键 没有冲突,则直接插入;
- 主键 或者 唯一键 如果冲突,则删除后再插入
- 两行被影响:证明此时主键或者唯一键发生冲突,原数据被删除,然后插入新数据
- 一行被影响:证明此时主键或者唯一键未发生冲突,正常插入数据
二、Retrieve:
关于查询读取,我们首先创建一个表
mysql> create table Retrieve_test(-> id int unsigned primary key auto_increment,-> name varchar(20) not null,-> chinese float default 0,-> math float default 0,-> english float default 0-> );
接着插入几列数据,来为后来的查询做好准备
select查询:
select是查询后面表达式的值:
所以,我们查询表中的数据,可以用select查询
select 列名(可以是*也就是全部查询,也可以是多列,中间用逗号隔开) from 表名;
全列查询:
用*表示全部,这样就能够查询整张表了
但是一般不建议使用这个,因为可能会使其查询的数据量很大,影响索引的使用
指定列查询:
比如说我要查每一个人的数学成绩:
select name,math from Retrieve_test;
并且这里是按照自己所选择的顺序来的,也可以查询字段相加的值,比如说查询总分的和:
select name,math+chinese+english from Retrieve_test;
as重命名:
对于那些所查询的字段,可以进行as 重命名:
比如将math+chinese+english重命名为total:
语法就是直接在待重命名的数字后面加上as 修改后的名称(as也可以省略)
对查询结果去重:
这里采用关键字distinct,将distinct紧跟在select后面即可:
select distinct 列名 from 表名;
如上,查询每个人的语文成绩,并对结果去重,
where条件:
比较运算符:
运算符/关键字 | 描述 | 示例/注意事项 |
---|---|---|
> , >= , < , <= | 大于、大于等于、小于、小于等于 | 直接比较数值、日期或字符串 |
= | 等于,NULL 不安全 | NULL = NULL 返回 NULL (非 TRUE ) |
<=> | 等于,NULL 安全 | NULL <=> NULL 返回 TRUE(1) |
!= , <> | 不等于 | 两种写法功能相同,如 5 != 3 返回 TRUE |
BETWEEN a0 AND a1 | 范围匹配(闭区间 [a0, a1] ) | value BETWEEN 10 AND 20 等价于 10 <= value <= 20 |
IN (option, ...) | 判断是否属于指定列表中的任意一个值 | value IN (1, 3, 5) 等价于 value = 1 OR value = 3 OR value = 5 |
IS NULL | 判断是否为 NULL | 仅用于 NULL 检查,如 col IS NULL |
IS NOT NULL | 判断是否不为 NULL | 如 col IS NOT NULL |
LIKE | 模糊匹配(% 匹配任意多个字符,_ 匹配单个字符) | 'abc%' 匹配以 abc 开头的字符串;'a_c' 匹配如 a1c 、adc 等 |
逻辑运算符:
运算符/关键字 | 描述 | 示例/注意事项 |
---|---|---|
AND | 多个条件必须都为 TRUE(1) ,结果才是 TRUE(1) | 条件1 AND 条件2 ,若任一条件为 FALSE(0) 或 NULL ,结果可能为 FALSE(0) 或 NULL |
OR | 任意一个条件为 TRUE(1) ,结果为 TRUE(1) | 条件1 OR 条件2 ,若任一条件为 TRUE(1) ,结果即为 TRUE(1) (忽略其他条件是否为 NULL ) |
NOT | 将条件的逻辑结果取反 | NOT 条件 ,若条件为 TRUE(1) ,结果为 FALSE(0) ;若为 FALSE(0) ,结果为 TRUE(1) |
where语句使用案例:
使用where语句的时候,是跟在表名后面的
查询英语120~140之间的人
除了使用大于小于符号,还可以使用between and
查询英语成绩90或者150的人
这里可以使用等号+or,也可以使用in (),后者优雅点感觉
查询姓孙的同学或者查询孙某同学
这里采用模糊匹配,为了方便观察,我们在插入孙权进去,接着查看的时候就会发现二者的不一样
查询总分在350以上的,并且将计算式子重命名为总分
但是要注意,在where中是不能使用重命名后的值的,因为条件筛选(where)执行顺序是在select 之前,所以在where的时候还看不知道as total
查询结果进行排序(order by):
ASC 为升序(从小到大),DESC 为降序(从大到小),默认为 ASC
select 字段名 from 表名 order by 待比较字段 desc/asc; //desc为降序排序, asc为升序
查询数学成绩从高到低:
查询各科成绩,按照语文成绩大小排名,如果语文成绩相等就按照数学成绩排名,如果数学成绩相等就按照英语成绩排名
select name,chinese,math,english from Retrieve_test order by chinese desc,math desc,english desc;
按照总分排名:
select name,chinese+math+english as 总分 from Retrieve_test order by 总分 desc;
这里重要的是为什么在order by后面可以使用重命名后的名字呢?但是where却不可以?
因为order by是对数据进行排序的,所以在这之前要先有数据,所以这个是在靠后的
where是对数据进行筛选,这个是先对数据进行筛选后,才会有数据
所以:
对于一套select语句来说:一定是from第一,where第二,select第三,order by第四
筛选分页结果
数据库是会很大的,那么想要提高效率查看是可以进行分页查询,这里采用limit
如果limit后面跟1个数字为N,那么就是从第一行往下数N行显示出来:
如果limit后面跟1个数字为N,M,那么就是从第N行(不包括第N行,也可以理解为下标)往下数M行显示出来:
还有一种写法:
select * from exam_result limit N offset M;
这里的意思和上述是一样的,但是这里看着清楚一点,就是从第N行往下数M行显示出来
三、Update:
对查询到的结果进行更新:
update 表名 set 列名 = XXX ... [where ...] [order by ...] [limit ...]
将曹老板的语文成绩改为115
将曹老板的语文成绩改为110,数学成绩改为110
和order by使用:将总成绩倒数后三位的同学的语文成绩加上20分
select name,chinese,chinese+math+english as 总分 from Retrieve_test order by 总分 limit 3;update Retrieve_test set chinese=chinese+20 order by chinese+math+english limit 3;
注意,这里不支持+=操作符
四、Delete:
删除表中数据:
delete from 表名 [where] [order by] [limit];
在使用的时候最好配合where筛选,不然一不小心就将所有数据删除了
将孙权的成绩删除
当进行删除后,auto_increment是不会受影响的,刚刚删除了8,下一次增加不是8,而是9
截断表:
truncate 表名;
首先创建一张表
接着向这张表中insert数据
此时表中数据如下:
此时进行截断表:
截断表后进行查找数据发现为空,并且发现会将auto_increment清空
五、对表进行去重操作:
这里的去重和之前的去重是不一样的,这里是直接对表进行操作,使去重后的表没有重复的数据,之前的去重是在查询的时候进行去重的
首先创建一个表:
接着向这个表中插入数据:
insert into test values (111,'张三'),(111,'李四'),(222,'王五'),(222,'赵六'),(222,'小七'),(333,'小八');
然后对这个表进行去重操作:
思路:
- 创建一张空表tmp,空表和原表test结构一样
- 将原表test的去重后的数据(这里采用select筛选去重)插入到新的空表tmp中
- 将原表test重命名为别的表,将去重后插入的空表tmp重命名为原表test即可
首先通过like创建空表tmp
接着进行去重查询:
将去重后的结果插入到新的空表tmp中
接着对原来的test进行重命名
rename table 原来的表名 to 重命名后的表名
最后将tmp重命名为test
这样就对test表进行去重了
六、聚合函数:
MySQL中存在函数,可以被我们调用,我们可以对一组数据进行聚合统计,对其使用的函数就叫做聚合函数
函数 | 说明 | 参数特性 |
---|---|---|
COUNT([DISTINCT] expr) | 返回查询数据的数量 | - expr 可为任意类型(包括非数字)- COUNT(*) 统计所有行(含 NULL )- COUNT(expr) 忽略 NULL 值 |
SUM([DISTINCT] expr) | 返回查询数据的总和 | - expr 必须为数值类型,否则结果无意义(可能返回 NULL 或报错) |
AVG([DISTINCT] expr) | 返回查询数据的平均值 | - expr 必须为数值类型,否则结果无意义(可能返回 NULL 或报错) |
MAX([DISTINCT] expr) | 返回查询数据的最大值 | - expr 可为数值、字符串、日期等可比较类型- 字符串按字典序比较,日期按时间顺序比较 |
MIN([DISTINCT] expr) | 返回查询数据的最小值 | - expr 可为数值、字符串、日期等可比较类型- 字符串按字典序比较,日期按时间顺序比较 |
示例:
对之前的Retrieve_test表进行使用聚合函数:
count(*)返回其总共有多少行
并且可以加上distinct,返回语文成绩不同的有多少个
并且在聚合函数后面还可以加上where判断
统计英语小于120分的人数:
avg平均聚合函数:
统计总成绩的平均分
查看英语成绩大于120分的同学其英语成绩最小有多少分
七、分组查询:
分组的目的是为了进行分组之后,方便进行聚合统计,这里将分组理解为分表
select column1, column2, ... from table group by column;
接下来对oracle 9i的经典测试表进行测试,来自:
DROP database IF EXISTS `scott`;
CREATE database IF NOT EXISTS `scott` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;USE `scott`;DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (`deptno` int(2) unsigned zerofill NOT NULL COMMENT ' 部门编号 ',`dname` varchar(14) DEFAULT NULL COMMENT ' 部门名称 ',`loc` varchar(13) DEFAULT NULL COMMENT ' 部门所在地点 '
);DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (`empno` int(6) unsigned zerofill NOT NULL COMMENT '雇员编号',`ename` varchar(10) DEFAULT NULL COMMENT '雇员姓名',`job` varchar(9) DEFAULT NULL COMMENT '雇员职位',`mgr` int(4) unsigned zerofill DEFAULT NULL COMMENT '雇员领导编号',`hiredate` datetime DEFAULT NULL COMMENT '雇佣时间',`sal` decimal(7,2) DEFAULT NULL COMMENT '工资月薪',`comm` decimal(7,2) DEFAULT NULL COMMENT '奖金',`deptno` int(2) unsigned zerofill DEFAULT NULL COMMENT '部门编号'
);DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade` (`grade` int(11) DEFAULT NULL COMMENT '等级',`losal` int(11) DEFAULT NULL COMMENT '此等级最低工资',`hisal` int(11) DEFAULT NULL COMMENT '此等级最高工资'
);insert into dept (deptno, dname, loc)
values (10, 'ACCOUNTING', 'NEW YORK');
insert into dept (deptno, dname, loc)
values (20, 'RESEARCH', 'DALLAS');
insert into dept (deptno, dname, loc)
values (30, 'SALES', 'CHICAGO');
insert into dept (deptno, dname, loc)
values (40, 'OPERATIONS', 'BOSTON');insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600, 300, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, null, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, null, 10);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3000, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7839, 'KING', 'PRESIDENT', null, '1981-11-17', 5000, null, 10);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7844, 'TURNER', 'SALESMAN', 7698,'1981-09-08', 1500, 0, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1100, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, null, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, null, 10);insert into salgrade (grade, losal, hisal) values (1, 700, 1200);
insert into salgrade (grade, losal, hisal) values (2, 1201, 1400);
insert into salgrade (grade, losal, hisal) values (3, 1401, 2000);
insert into salgrade (grade, losal, hisal) values (4, 2001, 3000);
insert into salgrade (grade, losal, hisal) values (5, 3001, 9999);
这里是创建了三张表,
如下是员工表,分别是empno员工号/ename员工姓名/job工作/mgr上级编号/hiredate受雇日期/sal薪金/comm佣金/deptno所属部门编号
如下是部门表,分别是deptno部门编号,dname部门名称,loc部门所在地
如下是薪资等级:
显示每个部门的平均工资和最高工资:
select max(sal) 最高工资,avg(sal) 平均工资 from emp;
这是对一张表emp显示最高工资和平均工资
在这个基础上对部门进行分组
select deptno,max(sal) 最高工资,avg(sal) 平均工资 from emp group by deptno;
根据部门和工作列出最低薪资和平均薪资
select deptno,job,min(sal) 最高工资,avg(sal) 平均工资 from emp group by deptno,job;
这里如果想看到最高工资是谁,那么就需要加上ename:
此时发现会报错,因为一般来说,只有在Group by后面出现了的,才能在前面显示出现,除了这些还有聚合函数可以显示出现,除此之外,一般不能再select后面跟具体的并不是分组条件的列
显示平均工资低于2000的部门和他的平均工资
首先分组聚合显示所有部门的平均工资:
select deptno,avg(sal) 平均工资 from emp group by deptno;
接着对上述的结果进行筛选,这里使用having而不是where,having对聚合结果进行筛选,其作用时间是在最后的,并且可以使用重命名
having和where的区别:
having和where都能够进行条件筛选,但是二者肯定是会有不同的
就像上述将having换成where就会报错,所以二者肯定是不能相互替换的
二者在应用场景和执行顺序有着显著的区别
核心区别:
WHERE | HAVING | |
---|---|---|
执行顺序 | 在数据分组前过滤(先过滤后分组) | 在数据分组后过滤(先分组后过滤) |
适用对象 | 过滤原始表的行(单行数据) | 过滤分组后的组(聚合结果) |
聚合函数 | 不能直接使用聚合函数(如SUM 、AVG ) | 必须使用聚合函数或分组字段 |
案例:显示平均工资低于2000的部门和他的平均工资,但是Smith不参与统计
select deptno,job,avg(sal) 平均工资 from emp where ename!='SMITH' group by deptno,job having 平均工资<2000;
如下这是执行顺序
where是对具体的任意列进行条件筛选
having是对分组聚合之后的结果进行条件筛选
二者条件筛选的阶段是不同的
总的来说:
WHERE:如果过滤条件不依赖分组或聚合函数,优先用WHERE
HAVING:当过滤条件涉及聚合函数或分组结果时,必须用HAVING