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