之前的 对数据表的操作 主要是进行列的增删查改,这里要对每条数据进行增删查改。 CRUD 即增加(Create)、查询(Retrieve)、更新(Update)、删除(Delete)四个单词的首字母缩写。
具体语句的执行顺序为: from子句->where 子句->group by 子句->having 子句->select 子句->order by 子句。 后面子句的别名不能在前面的子句使用。
一、插入数据
增加数据:
1.全列增加 insert into [表名称] values(表字段对应的值)
2.指定列进行插入 insert into[表名称] (表中列的名称,...) values(指定表字段对应的值...)
3.一次性插入多行数据
insert into[表名称] (表中列的名称,...) values(指定表字段对应的值...),(指定表字段对应的值...)
insert into [表名称] values(表字段对应的值),(表字段对应的值)
1.1. 插入查询结果
也可以将一个表的查询结果插入到另一个表中。
二、表的更新和替换
由于 主键 或者 唯一键 对应的值已经存在而导致插入失败,此时可以使用更新或者替换来进行解决。
2.1. 表的更新
insert ... on duplicate key updata old value = new value...
2.2. 替换
replace into 和 insert into的用法是类似的,insert每次插入一条新的数据,replace 会先查看表中是否有这条数据(主键或者唯一键),如果有先删除,然后插入一条新的数据,如果不存在则直接插入一条新的数据。
根据表中的主键或唯一键来判断,如果表中没有主键或唯一索引,那么replace into 就相当于 insert into,会直接插入一条数据。
三、select表的查询
3.1. 全列查询
select *from [表名称]; ‘ * '表示当前表的所有列。对于字段比较少,并且插入数据比较少的表,可以使用全列查询,查询的效率不会收到太大影响。如果一个表中字段比较多,或者数据量比较大,则全列查询会导致查询效率降。
3.2. 指定列查询
select [字段名称] …,from [表名称];
3.3. 查询字段为表达式并取别名
注意:这里math+10只是将查询结果+10,并不会改变表中的math。
3.4. 结果去重
加上关键字distinct进行查询。
3.4. where条件
比较运算符:
运算符 | 说明 |
---|
<, <= ,>,>=, | 小于,小于等于,大于,大于等于 | = | 等于,NULL 不安全,例如 NULL = NULL 的结果是 NULL | <=> | 等于,NULL 安全,例如 NULL <=> NULL 的结果是 TRUE(1) | !=, <> | 不等于 | between a0 and a1 | 范围匹配,[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) |
注意:别名不能出现在where条件中。因为查找的时候,是根据条件(where后面的条件)找的,即查找的时候是先看到条件,根据条件找到内容后,再根据select后面的语句进行显示。所以在查找的时候并不知道别名。
不过在from后对表取别名是可以的。
3.5. 结果排序
order by +排序条件 +排序方式; 。
order by子句中可以使用列别名。
ASC(默认方式)按照升序查询,DESC按照降序查询。
NULL 视为比任何值都小,降序出现在最下面。
3.6. 分页查询
对未知表进行查询时,最好加一条 limit 1,避免因为表中数据过大,查询全表数据导致数据库卡死。
limit +数字(显示多少行) offset +数字(偏移量); 或者 limit+数字(偏移量)+数字(显示多少行);
这两种写法的偏移量和行数进行了颠倒,但是当只有一个数字的时候,比如limit 5,它们显示的都是一样的,即显示前5行。
四、update表的更新
4.1. 对查询到的结果进行列值更新
上面的更新涉及到插入操作,如果只是单纯地想更新已经存在的内容,则可以使用下面的命令。 update + 表名 + set + 更改的列=新的值 where 限制条件 如果不加限制条件,则会将所有的列都会改掉。
五、delete删除表中的数据
删除的基本单位是一行,如果只是删除一行中的某一信息,则可以使用update进行清空。 delete from 表名+ where 限制条件;
如果不加限制条件,则会将整个表的数据都会删除,但是表还在。 drop table 表名; 才是将整个表都删除。
5.1. 截断表
truncate 表名; 可以直接将表名进行清空,它与delete有一些区别:
- 只能对整表操作,不能像 delete一样针对部分数据操作。
- 实际上 MySQL 不对数据操作,所以比 delete更快,但是truncate 在删除数据的时候,并不经过真正的事物,所以无法回滚。
- 会重置auto_increment项。
六、聚合函数
函数 | 说明 |
---|
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 | SUM([DISTINCT] expr) | 返回查询到的数据的 总和,会忽略null和非数字 | AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,会忽略null和非数字 | MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,如果没有结果则返回null | MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,如果没有结果则返回null |
七、group by子句的使用
group by 子句用来进行分组。
采用如下经典的测试用例表: scott_data.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);
导入数据库:
显示每个部门的平均工资和最高工资:
先对部门进行分组,然后使用聚合函数即可求出平均工资和最高工资。
显示每个部门的每种岗位的平均工资和最低工资:
首先按照部门进行分组,然后再对部门按照岗位分组。
7.1. 分组后使用聚合函数
显示平均工资低于2000的部门和它的平均工资:
-
首先统计各个部门的平均工资: -
然后在这些部门中找出小于2000工资的部门: 错误写法: 正确写法:
这主要是因为where后的条件表达式里不允许使用聚合函数,原因如下:
- where 子句的作用是在对查询结果进行分组前,将不符合where条件的数据去掉,即在分组之前过滤数据(一条数据一般被称为一条元组)。而聚合函数是对分组的结果进行运算,此时还没有分组。因此两者冲突,不能同时使用。必须先分好组以后再使用。
- having则是分组(group by)后的在组内进行筛选,此时可以使用聚合函数。
- 具体语句的执行顺序为: from子句->where 子句->group by 子句->having 子句->select 子句->order by 子句。
求有两个以上岗位工资小于3000的部门号,以及该部门的平均工资:
错误写法:
这种写法先对sal进行筛选(sal<3000),将筛选出来的元组按照部门号进行分组,然后过滤出组内元组条数大于2条的部门分组。但是接下来求avg(sal)则是对这些已经进行sal<3000筛选的部门分组进行求平均值,这些分组中每个元组的sal都是小于3000的,并不是该部门的全部元组。
正确写法:
这种写法用到了子查询,首先查出 有两个以上岗位工资小于3000的部门号 ,然后再用in过滤出属于这些部门号中的元组,然后按照部门号分组,此时我们就拿到这些部门号内的所有元组,而不是sal小于3000的元组。
八、复合查询
8.1. 子查询
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询。
显示工资最高的员工的名字和工作岗位
先找出emp表中最高的工资,然后在查找时找工资为最高工资的元组。
显示工资高于平均工资的员工信息
先求出emp表中的平均工资,然后在查找时找工资高于平均工资的元组。
8.1.1. 多行子查询
多行子查询是指子查询的结果返回单列多行数据。
查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10号自己。
首先找出10号部门的所有job,然后判断emp中job是否在所查询到的job中,并且部门号要不等于10。
- all :需要满足多行单列结果当中的所有,条件才满足。
显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号。
找出部门30的所有员工的工资,然后emp表中sal要比这些工资都高。
- any :只要满足多行单列结果当中的任一一个,则条件满足
显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)。
找出部门30号的所有员工的工资,然后emp表中sal要比这些工资任意一个高就可以。
当然也可以找出30号部门的最小工资,然后emp表中sal比这个最小工资大。
8.1.2. 多列子查询
多列子查询则是指查询返回多个列数据的子查询语句。
查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人。
我们需要同时找到deptno和job两列数据,上面的多行子查询都只是包含一列数据。
8.2. 在from子句中使用子查询
子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。
显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资。
-
首先,我们可以求出每个员工的姓名、部门、工资、平均工资: 但是这样有问题,平均工资是所有员工的平均工资,而ename和deptno则属于每个员工,所以它们冲突了,不能同时显示。 -
为了解决上面的问题,我们可以先按照部门进行分组,然后求出平均工资,然后和emp表进行笛卡尔积,然后根据部门号进行过滤。这样就找出了每个人的姓名、部门、工资,以及自己所在部门的平均工资。 -
最后找高于自己部门平均工资的员工,只需要在where后再加一个条件即可
查找每个部门工资最高的人的姓名、工资、部门、最高工资。
先按部门分组然后找出最高工资和部门号,然后和emp进行笛卡尔积,最后过滤。
显示每个部门的信息(部门名,编号,地址)和人员数量。
-
将员工表与部门表进行笛卡尔积,这样就能够拿到每个员工对应的部门信息 -
然后对部门号、部门名称、部门地址进行分组,并统计个数
-
对员工表表的人按照部门号进行分组并统计个数 -
将上面的表当成临时表,和员工表进行笛卡尔积,同时过滤。
8.3. 多表查询
实际开发中往往数据来自不同的表,所以需要多表查询。
显示雇员名、雇员工资以及所在部门的名字。
因为上面的数据来自emp和dept表,因此要联合查询。
在查找时,会先将两张表进行笛卡尔积,然后再从进行笛卡尔积之后的大表中根据where的限制条件找出合适的元组。
显示部门号为10的部门名,员工名和工资。
和上一个类似,但是限制条件中要多加一个部门号为10
显示各个员工的姓名,部门名称,工资,及工资级别。
涉及到三张表的查询
8.4. 自连接
自连接是指在同一张表连接查询,也就是自己和自己做笛卡尔积。 自连接时要对表进行重命名,否则会出现名字冲突的问题。
显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号)
可以使用子查询,先找出FORD的mgr字段然后再查找工号等于mgr。
也可以使用自连接,将leader表和worker表进行笛卡尔积,然后worker表中的mgr字段等于leader表中的empno同时worker表中的ename等于FORD。
8.5. 合并查询
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。union默认去重,union all是不去重。
实际上合并查询也可以在where中使用or来完成。
将工资大于2500或职位是MANAGER的人找出来。
九、表的内外连接
9.1. 内连接
内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,上面的多表查询都是内连接,也是在开发过程中使用的最多的连接查询。
select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;
显示SMITH的名字和部门名称。
这两种写法都可以,但是它们还是有一些区别:
- where是先生成两张表的笛卡尔积,然后根据where后面的条件进行过滤。
inner join ... on 条件 则是根据后面的条件on emp.deptno=dept.deptno and ename='SMITH' ,在生成笛卡尔积时就进行过滤,不满足这些条件的元组不会生成笛卡尔积。- 并且on后面的and如果改成where,它们的意义也不同。改成where以后,它们在
inner join ... on 条件 根据的条件则是on emp.deptno=dept.deptno ,然后根据where ename='SMITH' 进行过滤。
9.2. 外连接
外连接分为左外连接和右外连接。
9.2.1. 左外连接
如果联合查询,左侧的表完全显示我们就说是左外连接。 select 字段名 from 表名1 left join 表名2 on 连接条件;
比如对于下面两张表:
使用左连接时,当左边表和右边表没有匹配时,也会显示左边表的数据:
9.2.2. 右外连接
如果联合查询,右侧的表完全显示我们就说是右外连接。 select 字段 from 表名1 right join 表名2 on 连接条件;
使用右连接时,当左边表和右边表没有匹配时,也会显示右边表的数据:
|