【MySQL】表的CRUD

目录

一、Create:

单行插入:

多行插入:

插入否则更新:

插入否则替换:

二、Retrieve:

select查询:

全列查询:

指定列查询:

as重命名:

对查询结果去重:

where条件:

比较运算符:

逻辑运算符:

where语句使用案例:

[查询结果进行排序(order by):](#查询结果进行排序(order by):)

筛选分页结果

三、Update:

四、Delete:

删除表中数据:

截断表:

五、对表进行去重操作:

六、聚合函数:

七、分组查询:

having和where的区别:


什么是CRUD呢?

CRUD : C reate(创建), R etrieve(读取),U pdate(更新),Delete(删除)

一、Create:

首先,我们创建一张学生表,然后进行测试

sql 复制代码
mysql> create table student(
    -> id int unsigned primary key auto_increment,
    -> name varchar(20),
    -> QQ int unsigned unique,
    -> sex enum('男','女')
    -> );

单行插入:

单行插入在前面章节我们已经使用过很多次了,这里做下总结:

sql 复制代码
insert into 表名称(列属性, 不添加默认为全列插入) values (数据);

多行插入:

如果想插入多行,像上面那样一行一行插入比较麻烦,可以在values的后面进行逗号分割开()即可

插入否则更新:

如上,我们的表中是存在主键和唯一键的,所以在插入的时候,如果冲突了就会插入失败

主键冲突:

唯一键冲突:

我们可以在最后加上:

sql 复制代码
on duplicate key update XX=XXX ...;

其意思就是,首先插入,如果发现插入失败,就更新数据为后面的

  • 0 row affected: 表中有冲突数据,但冲突数据的值和 update 的值相等
  • 1 row affected: 表中没有冲突数据,数据被插入
  • 2 row affected: 表中有冲突数据,并且数据已经被更新

可以使用库函数来进行查看上一次影响了多少行

插入否则替换:

除了insert可以插入数据,还有replace也可以插入数据,replace与insert不同的是

  • 主键 或者 唯一键 没有冲突,则直接插入;
  • 主键 或者 唯一键 如果冲突,则删除后再插入
  • 两行被影响:证明此时主键或者唯一键发生冲突,原数据被删除,然后插入新数据
  • 一行被影响:证明此时主键或者唯一键未发生冲突,正常插入数据

二、Retrieve:

关于查询读取,我们首先创建一个表

sql 复制代码
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查询

sql 复制代码
select 列名(可以是*也就是全部查询,也可以是多列,中间用逗号隔开) from 表名;

全列查询:

用*表示全部,这样就能够查询整张表了

但是一般不建议使用这个,因为可能会使其查询的数据量很大,影响索引的使用

指定列查询:

比如说我要查每一个人的数学成绩:

sql 复制代码
select name,math from Retrieve_test;

并且这里是按照自己所选择的顺序来的,也可以查询字段相加的值,比如说查询总分的和:

sql 复制代码
select name,math+chinese+english from Retrieve_test;

as重命名:

对于那些所查询的字段,可以进行as 重命名:

比如将math+chinese+english重命名为total:

语法就是直接在待重命名的数字后面加上as 修改后的名称(as也可以省略)

对查询结果去重:

这里采用关键字distinct,将distinct紧跟在select后面即可:

sql 复制代码
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' 匹配如 a1cadc

逻辑运算符:

运算符/关键字 描述 示例/注意事项
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

sql 复制代码
select 字段名 from 表名 order by 待比较字段 desc/asc; //desc为降序排序, asc为升序

查询数学成绩从高到低:

查询各科成绩,按照语文成绩大小排名,如果语文成绩相等就按照数学成绩排名,如果数学成绩相等就按照英语成绩排名

sql 复制代码
select name,chinese,math,english from Retrieve_test order by chinese desc,math desc,english desc;

按照总分排名:

sql 复制代码
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行显示出来:

还有一种写法:

sql 复制代码
select * from exam_result limit N offset M;

这里的意思和上述是一样的,但是这里看着清楚一点,就是从第N行往下数M行显示出来

三、Update:

对查询到的结果进行更新:

sql 复制代码
update 表名 set 列名 = XXX ... [where ...] [order by ...] [limit ...]

将曹老板的语文成绩改为115

将曹老板的语文成绩改为110,数学成绩改为110

和order by使用:将总成绩倒数后三位的同学的语文成绩加上20分

sql 复制代码
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:

删除表中数据:

sql 复制代码
delete from 表名 [where] [order by] [limit];

在使用的时候最好配合where筛选,不然一不小心就将所有数据删除了

将孙权的成绩删除

当进行删除后,auto_increment是不会受影响的,刚刚删除了8,下一次增加不是8,而是9

截断表:

sql 复制代码
truncate 表名;

首先创建一张表

接着向这张表中insert数据

此时表中数据如下:

此时进行截断表:

截断表后进行查找数据发现为空,并且发现会将auto_increment清空

五、对表进行去重操作:

这里的去重和之前的去重是不一样的,这里是直接对表进行操作,使去重后的表没有重复的数据,之前的去重是在查询的时候进行去重的

首先创建一个表:

接着向这个表中插入数据:

sql 复制代码
insert into test values (111,'张三'),(111,'李四'),(222,'王五'),(222,'赵六'),(222,'小七'),(333,'小八');

然后对这个表进行去重操作:

思路:

  1. 创建一张空表tmp,空表和原表test结构一样
  2. 将原表test的去重后的数据(这里采用select筛选去重)插入到新的空表tmp中
  3. 将原表test重命名为别的表,将去重后插入的空表tmp重命名为原表test即可

首先通过like创建空表tmp

接着进行去重查询:

将去重后的结果插入到新的空表tmp中

接着对原来的test进行重命名

sql 复制代码
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分的同学其英语成绩最小有多少分

七、分组查询:

分组的目的是为了进行分组之后,方便进行聚合统计,这里将分组理解为分表

sql 复制代码
select column1, column2, ... from table group by column;

接下来对oracle 9i的经典测试表进行测试,来自:

sql 复制代码
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部门所在地

如下是薪资等级:

显示每个部门的平均工资和最高工资:

sql 复制代码
select max(sal) 最高工资,avg(sal) 平均工资 from emp;

这是对一张表emp显示最高工资和平均工资

在这个基础上对部门进行分组

sql 复制代码
select deptno,max(sal) 最高工资,avg(sal) 平均工资 from emp group by deptno;

根据部门和工作列出最低薪资和平均薪资

sql 复制代码
select deptno,job,min(sal) 最高工资,avg(sal) 平均工资 from emp group by deptno,job;

这里如果想看到最高工资是谁,那么就需要加上ename:

此时发现会报错,因为一般来说,只有在Group by后面出现了的,才能在前面显示出现,除了这些还有聚合函数可以显示出现,除此之外,一般不能再select后面跟具体的并不是分组条件的列

显示平均工资低于2000的部门和他的平均工资

首先分组聚合显示所有部门的平均工资:

sql 复制代码
select deptno,avg(sal) 平均工资 from emp group by deptno;

接着对上述的结果进行筛选,这里使用having而不是where,having对聚合结果进行筛选,其作用时间是在最后的,并且可以使用重命名

having和where的区别:

having和where都能够进行条件筛选,但是二者肯定是会有不同的

就像上述将having换成where就会报错,所以二者肯定是不能相互替换的

二者在应用场景和执行顺序有着显著的区别

核心区别:

| WHERE | HAVING |
|----------|--------------------------|----------------------|
| 执行顺序 | 在数据分组前过滤(先过滤后分组) | 在数据分组后过滤(先分组后过滤) |
| 适用对象 | 过滤原始表的行(单行数据) | 过滤分组后的组(聚合结果) |
| 聚合函数 | 不能直接使用聚合函数(如SUMAVG) | 必须使用聚合函数或分组字段 |

案例:显示平均工资低于2000的部门和他的平均工资,但是Smith不参与统计

sql 复制代码
select deptno,job,avg(sal) 平均工资 from emp where ename!='SMITH' group by deptno,job having 平均工资<2000;

如下这是执行顺序

where是对具体的任意列进行条件筛选

having是对分组聚合之后的结果进行条件筛选

二者条件筛选的阶段是不同的

总的来说:

WHERE:如果过滤条件不依赖分组或聚合函数,优先用WHERE

HAVING:当过滤条件涉及聚合函数或分组结果时,必须用HAVING

相关推荐
南隅。14 分钟前
【Redis】基础3:一些应用场景
数据库·redis
我是小酒1 小时前
Redis热key大key详解
数据库·redis·缓存
楠奕3 小时前
python上测试neo4j库
数据库·python·neo4j
当代红领巾5 小时前
windows 下 oracle 数据库的备份与还原
数据库
JuannyOh5 小时前
达梦数据库官方迁移工具SQLark:支持Oracle/MySQL/PostgreSQL迁移至达梦数据库!
mysql·postgresql·oracle·达梦数据库·迁移工具
新玉54015 小时前
SQL注入
数据库·sql·oracle
阿桨5 小时前
【Prometheus-OracleDB Exporter安装配置指南,开机自启】
数据库·oracle·centos·prometheus
赵渝强老师5 小时前
【赵渝强老师】使用TiDB的审计日志
数据库·tidb
code_shenbing5 小时前
.NET Core 数据库ORM框架用法简述
数据库·c#·.netcore·orm