文章目录
- MySQL表的增删改查
- 1. Create
- 1.1 单行数据插入
- 1.2 多行数据插入
- 1.3 插入否则更新
- 1.4 替换
- 2. Retrieve
- 2.1 SELECT 列
- 2.1.1 全列查询
- 2.1.2 指定列查询
- 2.1.3 查询字段为表达式
- 2.1.4 为查询结果指定别名
- 2.1.5 结果去重
- 2.2 WHERE 条件
- 2.2.1 英语不及格的同学及英语成绩(<60)
- 2.2.2 语文成绩在 [80, 90] 分的同学及语文成绩
- 2.2.3 数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
- 2.2.4 姓孙的同学 及 孙某同学
- 2.2.5 语文成绩好于英语成绩的同学
- 2.2.6 总分在 200 分以下的同学
- 2.2.7 语文成绩 > 80 并且不姓孙的同学
- 2.2.8 孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
- 2.2.9 NULL 的查询
- 2.3 结果排序
- 2.3.1 同学及数学成绩,按数学成绩升序显示
- 2.3.2 查询同学各门成绩,依次按 数学降序,英语降序,语文升序的方式显示
- 2.3.4 查询同学及总分,由高到低
- 2.3.5 查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
- 2.3.6 关于NULL的排序
- 2.4 筛选分页结果
- 2.4.1 从表开始连续读取5行
- 2.4.2 从1下标位置开始向下读取3行
- 2.4.3 按 id 进行分页,每页 3 条记录,分别显示 第 1、2、3 页
- 3. Update
- 3.1 将孙悟空同学的数学成绩变更为 80 分
- 3.2 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
- 3.3 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
- 3.4 将所有同学的语文成绩更新为原来的 2 倍
- 4. Delete
- 4.1 删除数据
- 4.1.1 删除孙悟空同学的考试成绩
- 4.1.2 删除总分最低同学的数据
- 4.1.3 删除整张表数据
- 4.2 截断表
- 5. 插入查询结果
- 6. 聚合函数
- 6.1 统计班级共有多少同学
- 6.2 统计本次考试的数学成绩分数个数
- 6.3 统计数学成绩总分
- 6.4 统计不及格英语成绩的平均分
- 6.5 统计平均总分
- 6.6 返回英语最高分
- 6.7 返回 > 70 分以上的数学最低分
- 7. group by子句的使用(分组查询)
- 7.1 显示每个部门的平均工资和最高工资
- 7.2 显示每个部门的每种岗位的平均工资和最低工资
- 深入理解分组
- 7.3 显示平均工资低于2000的部门和它的平均工资
- 7.4 一人不参与统计,显示每个部门、每种岗位的平均工资低于2000的工种
- 总结:having子句与where子句的区别
- 8. SQL中各语句的执行顺序
MySQL表的增删改查
表的CRUD操作 : Create(创建), Retrieve(读取),Update(更新),Delete(删除)
1. Create
语法:
INSERT [INTO] table_name[(column [, column] ...)]VALUES (value_list) [, (value_list)] ...value_list: value, [, value] ...
- 大写表示关键字,[]是可选项,可以选择不写
table_name
表示表名column
代表列,用来指定每个value_list
中的值应该插入到表中的哪一列value_list
代表某一列的值,与column
一一对应
案例:
mysql> create table students(-> id int unsigned primary key auto_increment,-> sn int unsigned unique key,-> name varchar(20) not null,-> qq varchar(32) unique key-> );
1.1 单行数据插入
指定列单行插入:
mysql> insert into students (sn,name,qq) values (123,'张飞','4567890');
Query OK, 1 row affected (0.04 sec)
单行全列插入:
在使用insert语句向学生表插入数据记录时,若不指定column
列,则按照表中默认的列顺序进行全列插入,因此插入时每条记录中的列值需要按表列顺序依次列出(即value_list
数量必须与定义表时列的数量及顺序保持一致)
mysql> insert into students values (10,124,'关羽','123456');
Query OK, 1 row affected (0.05 sec)
注:into
可以省略,但是为了符号插入语义,一般都写出来
1.2 多行数据插入
多行插入:插入的每条数据逗号隔开,达到一次插入多行的效果,全列插入或指定列插入都可以
多行全列插入
mysql> insert into students values (13, 127, '许攸', '10423456'), -> (14, 128, '许储', '104234568'),-> (15, 129, '诸葛亮', '104234569');
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0
多行指定列插入
mysql> insert into students (sn,name,qq) values (130, '孙权', '11423456'), -> (131, '吕布', '13234568');
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0
1.3 插入否则更新
向表中插入记录时,由于主键或者唯一键对应的值已经存在,发生主键冲突或唯一键冲突而导致插入失败
主键冲突:
可以选择性的进行同步更新操作,语法:
INSERT ... ON DUPLICATE KEY UPDATEcolumn = value [, column = value] ...
-
大写表示关键字,[]是可选项
-
ON DUPLICATE KEY
当发生重复key时,就执行后面的语句 -
UPDATE后面的
column=value
,表示当插入记录出现冲突时需要更新的列值
规则:
-
若表中不存在主键冲突或唯一键冲突,则直接插入数据
-
若表中存在主键冲突或唯一键冲突,则更新表中的数据
例如,插入的值发生主键冲突,则将表中冲突的列进行更新
mysql> insert into students values (13, 132, 'xuyou', '1111')-> on duplicate key update sn=132, name = 'xuyou', qq='1111';
Query OK, 2 rows affected (0.00 sec)
插入的值不存在,则直接插入数据。
此时on duplicate左边与右边的值可以不相等,不发生冲突时插入的是左边的值,发生冲突时就更新成右边的值
行插入否则更新的语句,可以通过受影响的数据行数来判断本次数据的插入情况:
0 rows affected
:表中有冲突数据,但冲突数据的值和指定更新的值相同1 row affected
:表中没有冲突数据,数据直接被插入2 rows affected
:表中有冲突数据,并且数据已经被更新
向表中插入数据,存在冲突且冲突数据的值和指定更新的值相同,可以通过 MySQL 函数获取受到影响的数据行数
SELECT ROW_COUNT();
1.4 替换
-
表中不存在主键冲突或唯一键冲突,则直接插入数据
-
表中存在主键冲突或唯一键冲突,则删除后再插入数据
语法:只需要在插入数据时将SQL语句中的INSERT改为REPLACE即可,其他相同
表中不存在冲突,直接插入数据
mysql> replace into students (sn, name, qq) values (140, '许攸','32145623');
Query OK, 1 rows affected (0.00 sec)
表中存在冲突,则删除后再插入数据
mysql> replace into students (sn, name, qq) values (140, '许攸1','32145623');
Query OK, 2 rows affected (0.00 sec)
由于主键会自增长且replace是删除后再插入,所以用于替换的行id将会使用下一个自增的id,我们可以观察到这里的id由原来的19变成20
执行该语句后,也可以通过受影响的数据行数来判断本次数据的插入情况:
1 row affected
: 表中没有冲突数据,数据被插入2 row affected
: 表中有冲突数据,删除后重新插入
2. Retrieve
语法:
SELECT[DISTINCT] {* | {column [, column] ...}[FROM table_name][WHERE ...][ORDER BY column [ASC | DESC], ...]LIMIT ...
案例:
-- 创建表结构
CREATE TABLE exam_result (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,name VARCHAR(20) NOT NULL COMMENT '同学姓名',chinese float DEFAULT 0.0 COMMENT '语文成绩',math float DEFAULT 0.0 COMMENT '数学成绩',english float DEFAULT 0.0 COMMENT '英语成绩'
);-- 插入测试数据
INSERT INTO exam_result (name, chinese, math, english) VALUES('唐三藏', 67, 98, 56),('孙悟空', 87, 78, 77),('猪悟能', 88, 98, 90),('曹孟德', 82, 84, 67),('刘玄德', 55, 85, 45),('孙权', 70, 73, 78),('宋公明', 75, 65, 30);
Query OK, 7 rows affected (0.00 sec)
Records: 7 Duplicates: 0 Warnings: 0
2.1 SELECT 列
2.1.1 全列查询
mysql> select * from 表名;
通常情况下不建议使用 * 进行全列查询
- 查询的列越多,意味着需要传输的数据量越大;
- 可能会影响到索引的使用。(索引待后面博客讲解)
2.1.2 指定列查询
mysql> select xxx(需要查询的列名,多列之间以逗号分隔) from 表名;
2.1.3 查询字段为表达式
select不仅能够用来查询数据,还可以用来计算某些表达式或执行某些函数。
在查询数据时,column列表中除了能罗列表中存在的列名外,也可以将表达式罗列到column列表中
- 表达式不包含字段
mysql> select name, math, 10 from exam_result;
相当于给这张表查询时增加一列
- 表达式包含一个或多个字段
mysql> select name, math, math+chinese+english from exam_result;
2.1.4 为查询结果指定别名
语法:
SELECT column [AS] alias_name [...] FROM table_name;
查询结果的列名太长时,可以对列名进行重命名。
mysql> select name, math, chinese + math + english as(可以省略) total from exam_result;
2.1.5 结果去重
直接在select后面带上distinct
关键字就可以对指定列数据进行去重
mysql> select distinct math from exam_result
2.2 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) |
2.2.1 英语不及格的同学及英语成绩(<60)
mysql> select name, english from exam_result where english<60;
2.2.2 语文成绩在 [80, 90] 分的同学及语文成绩
使用and
进行条件连接 或 between and
条件
mysql> select name, chinese from exam_result where chinese>=80 and chinese<=90;mysql> select name, chinese from exam_result where chinese between 80 and 90;
2.2.3 数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
使用 OR
进行条件连接
mysql> select name, math from exam_result-> where math = 58 or math = 59 or math = 98 or math = 99;
使用IN (option, ...)
条件来筛选
mysql> select name, math from exam_result where math in (58, 59, 98, 99);
2.2.4 姓孙的同学 及 孙某同学
通过模糊匹配来判断,使用到关键字like
- 姓孙的同学
% 匹配任意多个(包括 0 个)任意字符
mysql> select name from exam_result where name like '孙%';
- 孙某同学
_ 匹配严格的一个任意字符
mysql> select name from exam_result where name like '孙_';
2.2.5 语文成绩好于英语成绩的同学
WHERE 条件中比较运算符两侧都是字段
mysql> select name, chinese, english from exam_result where chinese > english;
2.2.6 总分在 200 分以下的同学
mysql> select name, chinese+english+math from exam_result where chinese+english+math<200;
注意:
where字句中不能使用select中指定的别名
查询数据时的执行顺序是上面的:123
- 先指明要查询的表的名称
- 再根据where字句筛选符合条件的记录
- 最后将符合条件的记录作为数据源来再依次执行select语句
在执行第二步时根本没有所谓的别名,第二步不认识total,所以会报错。
我们如果还是想以别名的形式显示,只在select语句时声明别名,where字句还是使用本名。
mysql> select name, chinese+english+math as total from exam_result -> where chinese + english + math < 200;
2.2.7 语文成绩 > 80 并且不姓孙的同学
我们可以将这个要求差解开,先查询语文成绩 > 80,再用like关键字查询姓孙同学,最后使用and将两句合为一句, like前加not
mysql> select name, chinese from exam_result where chinese > 80 and name not like '孙%';
2.2.8 孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
mysql> select name, chinese+english+math as 总分 from exam_result where name like '孙_' -> or (chinese+math+english > 200 and chinese < math and english > 80);
当条件过长时,可以添加括号
2.2.9 NULL 的查询
# 创建新表
mysql> create table test(-> id int,-> name varchar(20)-> );
Query OK, 0 rows affected (0.09 sec)# 插入数据
mysql> insert into test (id,name) values (1,'张三');
Query OK, 1 row affected (0.04 sec)
mysql> insert into test (id,name) values (null,'张三');
Query OK, 1 row affected (0.05 sec)
mysql> insert into test (id,name) values (1,null);
Query OK, 1 row affected (0.05 sec)
mysql> insert into test (id,name) values (null,null);
Query OK, 1 row affected (0.02 sec)
mysql> insert into test (id,name) values (1,'');
Query OK, 1 row affected (0.01 sec)
查看表
对null的查询:is null 与 is not null
mysql> select* from test where name is null;
mysql> select* from test where name is not null;
注意区分空串与NULL
查询空串
mysql> select* from test where name='';
注意:与NULL值作比较的时候应该使用<=>
运算符,使用=
运算符无法得到正确的查询结果,<=>
运算符不经常使用,判断为空或者不为空常使用is null
或is not null
-
=
运算符NULL不安全,使用=运算符将任何值与NULL作比较,得到的结果都是NULL -
<=>
运算符NULL安全,使用<=>
运算符将NULL和NULL作比较得到的结果为TRUE(1) -
!=
或<>
同样NULL不安全
2.3 结果排序
-- ASC 为升序(从小到大)
-- DESC 为降序(从大到小)
-- 默认为 ASC
SELECT ... FROM table_name [WHERE ...] ORDER BY column [ASC|DESC], [...];
注意:没有 ORDER BY 子句的查询,返回的顺序是未定义的,永远不要依赖这个顺序
2.3.1 同学及数学成绩,按数学成绩升序显示
mysql> select name,math from exam_result order by math asc;
不写asc,默认还是升序,建议还是写上
2.3.2 查询同学各门成绩,依次按 数学降序,英语降序,语文升序的方式显示
多字段排序,排序优先级随书写顺序
mysql> select name, math, english, chinese from exam_result order by math desc, -> english desc, chinese asc;
首先排序的是数学,数学成绩降序排序的,只有满足了数学降序,然后才到英语降序排序,最后到语文升序
若在表中出现相同的数学成绩就按照英语成绩排序,同理出现相同的英语成绩按照语文成绩排序
2.3.4 查询同学及总分,由高到低
mysql> select name, math+english+chinese from exam_result order by -> math+english+chinese desc;
order by这里能够使用select中指定的别名:
查询数据时的执行顺序是上面的:1234
- 先指明要查询的表的名称
- 若有where字句,则根据where字句筛选符合条件的记录
- 后将符合条件的记录作为数据源来再依次执行select语句
- 最后再通过order by子句对select语句的执行结果进行排序
即order by子句的执行是在select语句之后的,所以在order by子句中可以使用别名
这个问题的本质其实是:在order by之前先有了合适的数据,再排序
2.3.5 查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
mysql> select name, math from exam_result where name like '孙%' or name like '曹%' -> order by math desc;
2.3.6 关于NULL的排序
现在有这样一张表,最后一行的name是空串
我们对其中name, 升序及降序排列
发现无论在升序还是降序NULL都视为比任何值都小,升序出现在最上面,降序出现在最上面
2.4 筛选分页结果
-- 起始下标为 0-- 从 s 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT s, n;-- 从 0 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n;-- 从 s 开始,筛选 n 条结果,比第二种用法更明确,建议使用
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n OFFSET s;
- s代表开始位置(下标从0开始),n代表从指定位置开始连续读取多少条记录。
- 我们实际开始的位置是s下标+1
- 若没有给s,只给n,默认从第0开始(即第一行)
注意:对未知表进行查询时,最好加一条 LIMIT 1
,避免因为表中数据过大,查询全表数据导致数据库卡死
查询SQL中各语句的执行顺序为:where、select、order by、limit
limit的本质功能是显示,只有数据准备好了,才要显示
2.4.1 从表开始连续读取5行
mysql> select* from exam_result limit 5;
2.4.2 从1下标位置开始向下读取3行
mysql> select* from exam_result limit 1,3;
mysql> select* from exam_result limit 3 offset 1;
2.4.3 按 id 进行分页,每页 3 条记录,分别显示 第 1、2、3 页
提供两种写法
mysql> select* from exam_result limit 0,3;
mysql> select* from exam_result limit 3,3;
mysql> select* from exam_result limit 6,3;
mysql> select* from exam_result limit 3 offset 0;
mysql> select* from exam_result limit 3 offset 3;
mysql> select* from exam_result limit 3 offset 6;
3. Update
语法:
UPDATE table_name SET column = expr [, column = expr ...][WHERE ...] [ORDER BY ...] [LIMIT ...]
column=expr
,表示将记录中列名为column的值修改为expr- 在修改数据前需要先找到待修改的记录,update语句中的where、order by和limit就是用来定位数据的,若不进行条件限制,表中一列数据都会被修改
3.1 将孙悟空同学的数学成绩变更为 80 分
mysql> update exam_result set math=80 where name ='孙悟空';
先查看原有数据
修改后查看当前数据
3.2 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
mysql> update exam_result set math=60,chinese=70 where name ='曹孟德';
3.3 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
查看原来总分,并按升序排列观察前3
mysql> select name,math+chinese+english total from exam_result order by total asc;
直接取出倒数前3
mysql> select name,math+chinese+english total from exam_result order by total limit 3;
更新数值并观察最终结果,MySQL中不支持+=
这种复合赋值运算符
mysql> update exam_result set math = math+30 order by math+chinese+english asc limit 3;
在给倒数前3名同学数学加上30分后,这些可能不再是倒数前3了,最好整表察看一下
3.4 将所有同学的语文成绩更新为原来的 2 倍
注意:更新全表的语句慎用!
mysql> update exam_result set chinese=chinese*2;
4. Delete
4.1 删除数据
语法:
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
4.1.1 删除孙悟空同学的考试成绩
mysql> delete from exam_result where name='孙悟空';
4.1.2 删除总分最低同学的数据
mysql> delete from exam_result order by chinese+math+english asc limit 1;
4.1.3 删除整张表数据
注意:删除整表操作要慎用!
-- 准备测试表
CREATE TABLE for_delete (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(20)
);
Query OK, 0 rows affected (0.16 sec)-- 插入测试数据
INSERT INTO for_delete (name) VALUES ('A'), ('B'), ('C');
Query OK, 3 rows affected (1.05 sec)
Records: 3 Duplicates: 0 Warnings: 0
查看表
此时不通过where、order by和limit指明筛选条件,只指明删除数据的表名,这会删除整张表的数据
mysql> delete from for_delete;
但当我们在向表中插入数据且不指明自增长字段值时,发现插入数据对应的自增长id值是在原有基础上继续增长的
查看创建表的详细信息,发现有一个AUTO_INCREMENT=n
的字段仍然保存了下一个自增长对应的值,当delete语句删除整表数据时,并不会重置AUTO_INCREMENT=n
字段,因此删除整表数据后插入数据对应的自增长id值会在原有基础上继续增长。
4.2 截断表
语法:
TRUNCATE [TABLE] table_name
注意:这个操作慎用
-
只能对整表操作,不能像 DELETE 一样针对部分数据操作;
-
实际上 MySQL 不对数据操作,所以比 DELETE 更快,但是TRUNCATE在删除数据的时候,并不经过真正的事
物,所以无法回滚 -
会重置 AUTO_INCREMENT项
-- 准备测试表
CREATE TABLE for_truncate (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
);
Query OK, 0 rows affected (0.16 sec)-- 插入测试数据
INSERT INTO for_truncate (name) VALUES ('A'), ('B'), ('C');
Query OK, 3 rows affected (1.05 sec)
Records: 3 Duplicates: 0 Warnings: 0
查看表
mysql> truncate table for_truncate;
查看表详细信息,发现并没有保留AUTO_INCREMENT项
重新插入数据后,自增长id从1开始
5. 插入查询结果
语法:
INSERT INTO table_name [(column [, column ...])] SELECT ...
案例:删除表中的的重复记录,重复的数据只能有一份
-- 创建原数据表
CREATE TABLE duplicate_table (id int, name varchar(20));
Query OK, 0 rows affected (0.01 sec)-- 插入测试数据
INSERT INTO duplicate_table VALUES(100, 'aaa'),(100, 'aaa'),(200, 'bbb'),(200, 'bbb'),(200, 'bbb'),(300, 'ccc');
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
查看表
思路:
-
创建一张属性和原表一样的空表
-
利用distinct筛选出原表中去重后的数据插入到空表中
-
将原表名修改为其他,将新表名修改为原表名
创建一张空表 no_duplicate_table,结构和 duplicate_table 一样
mysql> create table no_duplicate_table like duplicate_table;
利用distinct 将 duplicate_table 的去重数据插入到 no_duplicate_table
mysql> insert into no_duplicate_table select distinct * from duplicate_table;
查看新表
对表名进行重命名
mysql> rename table duplicate_table to old_duplicate_table;
mysql> rename no_duplicate_table to duplicate_table;
最后通过rename方式进行:就是单纯的想等一切都就绪了,然后统一放入,更新,生效等。
6. 聚合函数
函数 | 说明 |
---|---|
COUNT([DISTINCT] expr) | 返回查询到的数据的数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的最小值,不是数字没有意义 |
6.1 统计班级共有多少同学
这样的一张表
mysql> select count(*) from student;
也可以在count后面添加一些说明
当然count(*),将 *更换成表达式也可以统计出表中的记录条数
6.2 统计本次考试的数学成绩分数个数
mysql> select count(distinct math) from exam_result;
- count(math) 统计的是全部成绩
- count(distinct math) 统计的是去重后成绩数量
6.3 统计数学成绩总分
mysql> select sum(math) from exam_result;
6.4 统计不及格英语成绩的平均分
使用where子句中筛选条件为英语成绩小于60分,后可使用sum/count也可使用avg
mysql> select sum(english)/count(english) from exam_result where english < 60;
6.5 统计平均总分
mysql> select avg(chinese+math+english) 平均总分 from exam_result;
6.6 返回英语最高分
mysql> select max(english) as maxEnglish from exam_result;
6.7 返回 > 70 分以上的数学最低分
mysql> select min(math) as minEnglish from exam_result where math > 70;
7. group by子句的使用(分组查询)
select column1, column2, .. from table group by column;
案例:
- 准备工作,创建一个雇员信息表(来自oracle 9i的经典测试表)
- EMP员工表
- DEPT部门表
- SALGRADE工资等级表
查看每张表
- dept部门表
- emp员工表
- salgrade工资等级表
将这张表通过rz指令上传到linux,后source 文件路径,下载下来,就可以使用该数据库
7.1 显示每个部门的平均工资和最高工资
mysql> select deptno, max(sal) 最高, avg(sal) 平均 from emp group by deptno;
7.2 显示每个部门的每种岗位的平均工资和最低工资
mysql> select deptno, job, avg(sal) 平均, min(sal) 最低 from emp group by deptno, job;
深入理解分组
我们还想在原有的基础上显示出员工姓名,会报错,因为ename在组内并不相同,无法被聚合压缩
mysql> select ename, deptno, job, avg(sal) 平均, min(sal) 最低 from emp group by deptno, -> job;
说明:
- 分组的目的是为了进行分组之后,方便进行聚合统计
- 这里group by后指定列名进行实际分组,使用该列的不同的行数据来进行分组的!
- 分组的条件(比如这里的deptno)在组内一定是相同的!— 可以被聚合压缩
分组
-
分组不就是把一组按照条件拆分成了多个组,进行各自组内的统计
-
分组(‘‘分表’’), 不就是把一张表按照条件在逻辑上拆成了多个子表,然后分别对各自的子表进行聚合统计
7.3 显示平均工资低于2000的部门和它的平均工资
分为两步:
-
统计各个部门的平均工资
-
having和group by配合使用,对group by结果进行过滤
统计各个部门的平均工资
mysql> select deptno, avg(sal) 平均工资 from emp group by deptno;
用having对group by的结果过滤
mysql> select deptno, avg(sal) 平均工资 from emp group by deptno having 平均工资 < 2000;
7.4 一人不参与统计,显示每个部门、每种岗位的平均工资低于2000的工种
SMITH员工不参与统计
mysql> select deptno,job,avg(sal) 平均工资 from emp where ename!='SMITH' -> group by deptno,job having 平均工资<2000;
总结:having子句与where子句的区别
where
子句放在表名后面,而having
子句必须搭配group by
子句使用,放在group by
子句的后面,执行顺序不同。where
子句对具体的任意列进行条件筛选,having
子句对分组聚合之后的结果进行条件筛选- 分组聚合只能使用having不能使用where,但是只有一张表的的筛选既可以用having也可用where(不建议)
对结果的小小理解(小小建模):
- 不要单纯的认为,只有磁盘上表结构导入到mysql中,真实存在的表,才叫做表
- 中间筛选出来的,包括最终结果,全部都可以认为是逻辑上的表,''MySQL一切皆表"
- 未来只要我们能够处理好单表的CURD, 所有的sql场景,我们全部都能用统一的方式进行
8. SQL中各语句的执行顺序
- 根据where子句筛选出符合条件的记录
- 根据group by子句对数据进行分组
- 将分组后的数据依次执行select语句
- 根据having子句对分组后的数据进行进一步筛选
- 根据order by子句对数据进行排序
- 根据limit子句筛选若干条记录进行显示
面试题:SQL查询中各个关键字的执行先后顺序
from > on> join > where > group by > with > having > select > distinct > order by > limit