【MySQL】对表中数据的操作

本期给大家带来的是MySQL下对表中数据的增删查改操作


目录

一、对表插入数据

[1.1 单行数据插入](#1.1 单行数据插入)

[1.2 多行数据插入](#1.2 多行数据插入)

[1.3 插入冲突时更新数据](#1.3 插入冲突时更新数据)

[1.4 替换式插入](#1.4 替换式插入)

[1.5 插入查询结果](#1.5 插入查询结果)

二、对表中数据进行查询

[2.1 基本select](#2.1 基本select)

[2.1.1 使用select查询表中数据](#2.1.1 使用select查询表中数据)

[2.1.2 使用select进行计算](#2.1.2 使用select进行计算)

[2.1.3 在select语句中使用as对列自定义命名](#2.1.3 在select语句中使用as对列自定义命名)

[2.1.4 对查询结果进行去重](#2.1.4 对查询结果进行去重)

[2.1.5 where条件](#2.1.5 where条件)

[2.1.6 对查询结果进行排序](#2.1.6 对查询结果进行排序)

[2.1.7 分页显示筛选结果](#2.1.7 分页显示筛选结果)

[2.2 分组聚合查询](#2.2 分组聚合查询)

三、对表中的数据进行修改

四、删除表中的数据

五、截断表

六、聚合函数


一、对表插入数据

我们之前在表的操作中提了一下向表中插入数据,下面我们来详细讲解

1.1 单行数据插入

我们可以使用下面的语句对表做数据插入:

sql 复制代码
insert into 想要插入的表名(所要插入的列1,所要插入的列2...) values(数据1,数据2...);

上面语句在使用时into关键字可省略

在表名后面我们可以使用()在里面指定要插入的列,下面用这张表来演示一下:

当然表名后面我们也可以省略()进行全列插入:

1.2 多行数据插入

上面的方法每次只能插入一行数据,效率不高,我们可以在values关键字后面多加几个()用来一次插入多行数据:

sql 复制代码
insert into 表名(列1,列2...) values(数据1,数据2...),(数据1,数据2...), ...;

上面语句在使用时into关键字可省略

下面我们来演示一下,同样还是刚才的表:

多行指定列插入:

多行全列插入:

1.3 插入冲突时更新数据

我们向表中插入数据时,有时会因为主键、唯一建之类的约束发生数据冲突:

这样子我们就不能将数据插入到表中,但是使用下列语法可以在插入数据发生冲突时,更新表中冲突数据所在行:

sql 复制代码
insert into 表名(列1,...) values (数据1,...) on duplicate key update 列名1=数据1 ,列名2=数据2 ,...;

我们来试试看:

我们可以看到上述语句在插入'i'这个数据时因为id的主键冲突肯定会失败,但是后面的on duplicate key update语句则意味着插入冲突时,将冲突数据所在行的name列数据改为'i'、telephone列数据改为'12345689'

可以看到修改非常成功,下面我们来看看该语句如果插入时没有发生冲突,系统会干啥:

可以看到当插入语句没有发生冲突时,系统会直接插入数据,不会再执行后面的更新语句

下面我们试试看当发生插入冲突时,但是更新语句更新的数据跟冲突数据一样会怎么样:

我们发现:当发生插入冲突时,但是更新语句更新的数据跟冲突数据一样,系统会什么都不做

所以使用该语句时,我们可以根据系统执行的反馈来确定数据是否做了更改:

-- 0 row affected: 表中有冲突数据,但冲突数据的值和 update 的值相等

-- 1 row affected: 表中没有冲突数据,数据被插入

-- 2 row affected: 表中有冲突数据,并且数据已经被更新

1.4 替换式插入

sql 复制代码
replace into 表名 (列名1, 列名2, ...) values (数据1, 数据2, ...);

使用上述语句可以进行替换式插入:主键或唯一键没有冲突,则直接插入;如果冲突,则删除表中原冲突数据后再插入

举例演示:

可以看到插入的数据和表中数据没有冲突,进行了直接插入

下面要插入的数据和表中原数据的id列发生了主键冲突:

可以看到发生冲突的原数据直接全部被替换为插入的数据

1.5 插入查询结果

该内容涉及到下文的select语句,建议看完基本select后再回头来看该部分内容

insert不仅仅可以插入我们自己手动输入的数据,还可以拿取select语句的数据对表进行插入:

sql 复制代码
INSERT INTO 表名 [(列名1,列名2...)] SELECT ...

光说概念太生涩了,我们实际举例来说明:

对于上面这张表,现在的要求是对其数据内容进行去重

去重?使用distinct关键字不就行了吗?

distinct虽然可以对查询结果进行去重,但是不能修改表中原始数据,所以我们要重新创建一张空表,将去重结果存入空表中,再将空表重命名为原表名称(原表可以改为其他名或者删除),这样子就可以实现对表中数据进行去重了。

下面我们一步步来:

创建空表时,我们可以使用原始的create语句一个个来定义和原表一样的列,不过在这里推荐使用like直接创建结构跟原表一模一样的空表:

再使用select语句来拿到原表的去重数据:

接着将select语句的去重结果使用insert语句插入到空表中:

最后将两个表重命名一下就完成了:

二、对表中数据进行查询

2.1 基本select

我们对表中数据进行查询时少不了select语句,其基本语法为:

sql 复制代码
SELECT
[DISTINCT] [[*] [column , column] ...]
[FROM table_name]
[WHERE ...]
[ORDER BY column [ASC | DESC], ...]
[LIMIT ...]

可以看到select语句可以跟上很多条件,下面我们来一一举例介绍

我们先创建一个表,再向其插入些数据:

2.1.1 使用select查询表中数据

如果我们想要查询表中全部的数据可以使用下面的语句:

sql 复制代码
select * from 表名;

上面的*是通配符,表示全部

我们来试试看:

如果我们想要查询表中某几列的数据可以使用下面的语句:

sql 复制代码
select 列名1,列名2,... from 表名;

例如:

2.1.2 使用select进行计算

select语句不仅仅能查询,还能进行计算:

既然可以进行计算的话,我们拿表中的数据来试试看:

那这样我们就可以打印出每个学生的总分:

2.1.3 在select语句中使用as对列自定义命名

上面的总分列名太长了,我们可以使用as关键字来对打印的列名进行重命名:

当然as也可以省略:

2.1.4 对查询结果进行去重

我们可以在select后面加上distinct关键字来对查询结果去重

例如math列原数据:

有两个85相同数据,现在我们来进行去重:

2.1.5 where条件

我们可以在select后面加上where条件句来筛选符号条件的数据,where后面常用的运算符有:

比较运算符:

运算符 说明
>, >=, <, <= 大于,大于等于,小于,小于等于
= 等于,NULL 不安全,例如 NULL = NULL 的结果是 NULL
<=> 等于,NULL 安全,例如 NULL NULL 的结果是 TRUE(1)
!=, <> 不等于
BETWEEN n1 AND n1 范围匹配,[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1)
IN (option, ...) 如果是 option 中的任意一个,返回 TRUE(1)
IS NULL 是 NULL
IS NOT NULL 不是 NULL
LIKE 模糊匹配。% 表示任意多个(包括 0 个)任意字符;_ 表示任意一个字符

逻辑运算符:

运算符 说明
AND 多个条件必须都为 TRUE(1),结果才是 TRUE(1)
OR 任意一个条件为 TRUE(1), 结果为 TRUE(1)
NOT 条件为 TRUE(1),结果为 FALSE(0)

下面我们拿案例来细细分析这些运算符的使用:

(1)英语不及格的同学及英语成绩 ( < 60 ):

(2)语文成绩在 [80, 90] 分的同学及语文成绩:

或者使用between and条件句:

(3)数学成绩是 12 或者 65 或者 98 或者 100 分的同学及数学成绩:

上面使用or条件句过于复杂,我们可以换成in条件句:

(4)姓名以a开头的同学及a某同学:

为了演示该例子我们再插入两组数据:

在这里我们需要用到like进行模糊查找,在字符a后面加上%表示a字符后可以跟任意多个(包括 0 个)任意字符,这样子我们就可以招找到姓名以a开头的同学了:

在字符a后面加上_表示a字符后只能跟一个任意字符 ,这样我们就可以查到a某同学:

(5)语文成绩好于英语成绩的同学

(6)总分在 200 分以下的同学

当然我们对总分这一列重命名:

那既然重命名了总分这一列,where字句的后面直接用重命名的列不是更方便吗?

但是系统是不支持的,要知道执行这句指令时,先要执行计算where语句后面的条件,再拿到select语句中去筛选。所以在where执行时总分这一列还没有被重命名,系统会自动报错。

(7)语文成绩 > 80 并且姓名不以a开头的同学

(8)姓名以b开头的同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80

当条件过多时,可以使用()来将多个条件视为一个整体:

2.1.6 对查询结果进行排序

我们可以使用order by语句对select的查询结果进行排序:

sql 复制代码
SELECT ... FROM table_name [WHERE ...]
ORDER BY column [ASC|DESC], [...];

-- ASC 为升序(从小到大),DESC 为降序(从大到小),默认为 ASC

要注意NULL视为比任何值都小!

下面我们来进行演示:

(1)查询同学及数学成绩,按数学成绩升序显示

(2)查询同学及英语成绩,按英语成绩降序显示

(3)查询同学各门成绩,依次按数学降序,英语升序,语文升序的方式显示

即数学成绩升序排列,如果相等数学成绩相等按英语成绩升序,如果英语成绩相等按语文成绩升序:

(4)查询同学及总分,由高到低排序

我们可以看到order by语句可以使用select语句前面重命名的列名,和where语句不一样。

这是因为select在选择完数据后才会交给order by语句来排序,在选择完数据时已经对列进行了重命名,所以order by语句可以使用select语句前面重命名的列名。

2.1.7 分页显示筛选结果

我们可以使用limit关键字来对我们select的筛选结果进行部分显示,其语法有三种:

从第一行开始向下显示n行:

sql 复制代码
select ... limit n;

从第n1行(0为第一行)开始向下显示n2行:

sql 复制代码
select ... limit n1,n2;

从第n2行(0为第一行)开始向下显示n1行:

sql 复制代码
select ... limit n1 offset n2;

建议:对未知表进行查询时,最好加一条 LIMIT 1,避免因为表中数据过大,查询全表数据导致数据库卡死。

下面来演示一下:

从第一行开始,向下显示3行:

从第4行开始,向下显示2行:

如此一来就可以进行对表进行分页显示了,比如我们每一页显示该表的3行数据:

或者

2.2 分组聚合查询

该内容涉及到下文的聚合函数,建议看完聚合函数后再回头来看该部分内容

2.2.1 使用group by对数据进行分组

在select中使用group by子句可以对指定列进行分组查询:

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

分组查询有什么用呢?别急,我们下面用实例一一说明:

下面我们创建一个雇员信息表(来自oracle 9i的经典测试表)(该表的sql文件已上传到资源中,大家可以下载直接使用,如果下载不了就使用下面的建表语句):

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);

我们使用source语句将该表导入到MySQL中:

导入后我们查看一下该数据库 :

下面我们正式开始进行分组查询:

(1)显示每个部门的平均工资和最高工资

我们可以使用聚合函数对所有员工的平均工资和最高工资进行统计:

但是我们的目的要将所有员工以所在部门为单位统计,所以在这里group by语句就要上场了:

这样子我们可以看到数据被分成了三份,但是每组数据具体属于哪个部门还看不出来,我们可以打印数据所在deptno列来看看:

从上述例子我们可以看出:分组,就是把一组数据按照条件拆成了多个组,进行各自组内的统计分组("分表"),就是把一张表按照条件在逻辑上拆成了多个子表,然后分别对各自的子表进行聚合统计

(2)显示每个部门的每种岗位的平均工资和最低工资

我们可以看到该需求需要我们现将数据进行按部门分组,按部门分完组后再按岗位进行分组,最后将每组的数据做统计:

2.2.1 使用having对分组后的数据进行条件判断

下面我们有一个需求:

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

我们可以将这个需求分为两部分:

一:统计出来每一个部门的平均工资结果先聚合出来

二:再对聚合的结果进行判断,看其是否小于2000

我们先来实现第一步:

第二步我们要用到一个关键字having,可以对group by的结果进行条件判断(where无法对group by的分组结果进行条件判断):

三、对表中的数据进行修改

对表中数据进行修改时我们会用的update:

sql 复制代码
update 表名 set 要修改的列名1=数据1,列名2=数据2,... [where ...] [order by ...] [limit ...];

下面我们开始举例说明:

(1)将a同学的数学成绩变更为 80 分

这里要注意了,如果不加后面的where语句默认对表math列的全部数据进行修改,这是很危险的!

(2)将总成绩倒数前三的 3 位同学的数学成绩加上 30 分

四、删除表中的数据

对表中的数据做删会用到delete关键字:

sql 复制代码
DELETE FROM 表名 [WHERE ...] [ORDER BY ...] [LIMIT ...]

如果DELETE FROM 表名后面不接任何条件句回删除整张表中的数据!

下面我们来举例:

(1)删除a同学的考试成绩

(2)删除总分倒数第一同学的考试成绩

(2)删除表中全部数据

我们以下面这张表为列,删除其内部全部数据:

我们可以看到delete确实删除了表中所有数据,但是自增建的默认值没没有发生变化,所以使用delete删除表中所有数据并不会重置自增建!

五、截断表

我们可以使用下面的语句直接删除表中的所有数据(注意:这个操作慎用 ):

sql 复制代码
TRUNCATE [TABLE] 表名;

要强调一下:

  1. 只能对整表操作,不能像 DELETE 一样针对部分数据操作;
  2. 实际上 MySQL 不对数据操作,所以比 DELETE 更快,但是TRUNCATE在删除数据的时候,并不经过真正的事物,所以无法回滚
  3. 会重置 AUTO_INCREMENT

下面拿这张表来操作一下:

我们可以看到经过truncate之后,该表不仅仅所有数据都清空了,并且建表语句中AUTO_INCREMENT也没有了

我们再插入数据试试看:

我们可以看到AUTO_INCREMENT已经被重置了

六、聚合函数

MySQL内有一些函数可供我们调用,下面我们来提前讲一讲聚合函数为分组查询做准备:

函数 说明
COUNT([DISTINCT] expr) 返回查询到的数据的数量
SUM([DISTINCT] expr) 返回查询到的数据的总和,不是数字没有意义
AVG([DISTINCT] expr) 返回查询到的数据的平均值,不是数字没有意义
MAX([DISTINCT] expr) 返回查询到的数据的最大值,不是数字没有意义
MIN([DISTINCT] expr) 返回查询到的数据的最小值,不是数字没有意义

下面我们继续举例:

(1)统计共有多少个学生

当然我们也可以对查询结果进行重命名:

(2)统计本次考试的数学成绩个数

(3)统计本次考试的数学成绩分数个数(去除重复的分数)

(4)统计数学成绩总分

(5)统计数学大于90分的人数

(6)统计全班数学平均分

或者:

(7)统计全班总分平均分

(8)返回英语最高分

(9)返回 > 70 分以上的数学最低分


该篇博客知识点较多,还请大家慢慢反复观看

感谢各位的阅览~我们下期见~

更多MySQL技能请看:http://t.csdn.cn/W9dQl

博主努力更新中~

相关推荐
vip4512 分钟前
Linux 经典面试八股文
linux
大霞上仙4 分钟前
Ubuntu系统电脑没有WiFi适配器
linux·运维·电脑
小码的头发丝、31 分钟前
Django中ListView 和 DetailView类的区别
数据库·python·django
小兜全糖(xdqt)38 分钟前
mysql数据同步到sql server
mysql·adb
Karoku06641 分钟前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
孤客网络科技工作室1 小时前
VMware 虚拟机使用教程及 Kali Linux 安装指南
linux·虚拟机·kali linux
周全全1 小时前
MySQL报错解决:The user specified as a definer (‘root‘@‘%‘) does not exist
android·数据库·mysql
白云如幻1 小时前
MySQL的分组函数
数据库·mysql
荒川之神2 小时前
ORACLE 闪回技术简介
数据库·oracle
颇有几分姿色2 小时前
深入理解 Linux 内存管理:free 命令详解
linux·运维·服务器