【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

相关推荐
HashData酷克数据几秒前
官宣:Apache Cloudberry (Incubating) 2.0.0 发布!
数据库·开源·apache·cloudberry
秋难降1 分钟前
SQL 索引突然 “罢工”?快来看看为什么
数据库·后端·sql
TDengine (老段)31 分钟前
TDengine 时间函数 TODAY() 用户手册
大数据·数据库·物联网·oracle·时序数据库·tdengine·涛思数据
码界奇点40 分钟前
KingbaseES一体化架构与多层防护体系如何保障企业级数据库的持续稳定与弹性扩展
数据库·架构·可用性测试
悟乙己1 小时前
数据科学家如何更好地展示自己的能力
大数据·数据库·数据科学家
皆过客,揽星河1 小时前
mysql进阶语法(视图)
数据库·sql·mysql·mysql基础语法·mysql进阶语法·视图创建修改删除
tuokuac2 小时前
Redis 的相关文件作用
数据库·redis·缓存
鹧鸪云光伏与储能软件开发3 小时前
投资储能项目能赚多少钱?小程序帮你测算
运维·数据库·小程序·光伏·光伏设计软件·光伏设计
2301_779503765 小时前
MySQL主从同步--主从复制进阶
数据库·mysql
beijingliushao5 小时前
58-正则表达式
数据库·python·mysql·正则表达式