Java阶段二Day10
文章目录
- Java阶段二Day10
- DQL
- GROUP BY 分组
- 按单字段分组
- 例
- 按多字段分组
- 例
- 按照聚合函数的结果排序
- 例
- HAVING子句
- 问题
- 错误
- 原因
- HAVING子句的应用
- HAVING和WHERE的区别
- 例
- 子查询 (SubQuery)
- 概念
- 应用场景
- 子查询分类
- 在DQL中使用子查询
- 单行单列子查询
- 例
- 多行单列子查询
- 例
- 在DML语句中使用子查询
- 例
- 在DDL语句中使用子查询
- 例
- 关联查询(重点)
- 定义
- 关联关系
- 关联关系分类
- 连接条件
- 语法
- 例
- 连接条件与过滤条件同时满足
- 例
- N张表关联
- 例
- 综合练习
- 题干
- 答案
- 关联查询中使用聚合函数
- 例
- 综合练习
- 题干
- 答案
DQL
GROUP BY 分组
GROUP BY子句可以将结果集按照指定字段值相同的记录进行分组,配合聚合函数可以实现组内统计。
- 在SELECT子句中出现聚合函数时,那么不在聚合函数中的字段都要出现在GROUP BY子句中。
- GROUP BY子句是配合聚合函数使用的,如果SELECT子句中没有聚合函数,通常不写GROUP BY。
按单字段分组
例
-
查看每种职位的老师平均工资是多少?
SELECT AVG(salary),title FROM teacher GROUP BY title
-
查看每个班级各多少人?
班级号相同的学生应该是同一个班,因此按照班级号相同的记录分组,组内求记录数 SELECT COUNT(*),class_id FROM student GROUP BY class_id
-
查看学生每种职位各多少人,以及最大生日和最小生日?
SELECT COUNT(*) '人数',MIN(birth) '最大生日',MAX(birth) '最小生日',job FROM student GROUP BY job
按多字段分组
GROUP BY后面指定多个字段时,分组方式为:这些字段值都一样的记录看作一组
例
-
查看同班级同性别的学生分别多少人?
SELECT COUNT(*),class_id,gender FROM student GROUP BY class_id,gender 班级号相同且性别相同的记录分为一组
-
查看每个班每种职位各多少人?
SELECT COUNT(*),class_id,job FROM student GROUP BY class_id,job
按照聚合函数的结果排序
例
-
查看每个科目老师的平均工资排名?
SELECT AVG(salary),subject_id FROM teacher GROUP BY subject_id ORDER BY AVG(salary) DESC 好的书写习惯:当SELECT子句中出现了函数或表达式时,通常应当为该字段添加别名。 ORDER BY子句也可以根据别名对该结果集按字段排序 SELECT AVG(salary) avg_sal,subject_id FROM teacher GROUP BY subject_id ORDER BY avg_sal DESC
HAVING子句
HAVING子句用于分组中的过滤条件
问题
-
查看每个科目老师的平均工资?但是仅查看平局工资高于6000的那些.
SELECT AVG(salary),subject_id FROM teacher WHERE AVG(salary)>6000 GROUP BY subject_id
错误
聚合函数不能在WHERE子句中使用
原因
WHERE子句中使用聚合函数错误的原因是:过滤时机不对。
- WHERE的过滤时机是在第一次检索表中每一条记录时进行过滤的,用于确定结果集的记录
- 聚合函数的统计结果进行过滤,前提:
- 先将表中数据检索出结果集
- 才能将结果集分组
- 分组后才能根据聚合函数统计结果
- 最后再根据统计结果过滤
- 聚合函数的过滤是在WHERE之后进行的
HAVING子句的应用
HAVING子句是紧跟在GOURP BY子句之后,用于对分组进行过滤的子句。
HAVING和WHERE的区别
- WHERE是在第一次检索表数据时用于添加过滤条件。确定结果集
- HAVING是在GROUP BY之后(将结果集分组之后)添加过滤条件的,用于确定分组。
- 过滤时机不同,作用不同
例
-
查看每个科目老师的平均工资?但是仅查看平局工资高于6000的那些.
子句执行顺序 SELECT AVG(salary),subject_id 4 符合要求的分组统计对应信息 FROM teacher 1 数据来源,数据从teacher表查询 GROUP BY subject_id 2 确定分组,按科目分组(比如6组) HAVING AVG(salary)>6000 3 过滤分组,比如只有3组符合要求
-
查看每个科目老师的平均工资,前提是该科目老师最高工资要超过9000
执行顺序 SELECT AVG(salary),subject_id 4 查看符合要求的分组的统计结果 FROM teacher 1 确定数据来源 GROUP BY subject_id 2 确定分成几组 HAVING MAX(salary)>9000 3 确定哪些分组符合要求
-
查看科目老师的工资总和是多少?前提是该科老师的平均奖金要高于4000.
SELECT SUM(salary),subject_id FROM teacher GROUP BY subject_id HAVING AVG(IFNULL(comm,0))>4000
-
查看各科目男老师的平均工资是多少?前提是该科目老师最低工资高于4000.
SELECT AVG(salary),subject_id FROM teacher WHERE gender='男' GROUP BY subject_id HAVING MIN(salary)>4000
子查询 (SubQuery)
概念
嵌套在一个SQL语句中的DQL语句,该DQL被称为子查询
应用场景
- DQL中使用子查询
- 在SELECT子句中,将当前子查询结果作为一个字段展示
- 在WHERE子句中,将当前子查询结果作为过滤条件使用(最常用的场景)
- DML中使用:将一个查询结果集用于增删改操作
- DDL中使用
- 在创建表时可以将一个子查询结果集当作表创建
- 在创建视图时使用一个子查询结果集
子查询分类
- 单行单列子查询,该子查询的结果集只有一个值
- 多行单列子查询,该子查询结果集是多个值
- 多列子查询(多行多列子查询|多行多列子查询),将该子查询当作一张表使用
在DQL中使用子查询
单行单列子查询
例
-
查看比范传奇工资高的老师都有谁?
1:未知条件:范传奇的工资是多少? SELECT salary FROM teacher WHERE name='范传奇' ==>3000 2:谁的工资高于3000? SELECT name,salary FROM teacher WHERE salary>3000 以java的思想 int sal = SELECT salary FROM teacher WHERE name='范传奇'; sal=>3000 使用该变量 SELECT name,salary FROM teacher WHERE salary>sal 合并代码 SELECT name,salary FROM teacher WHERE salary>SELECT salary FROM teacher WHERE name='范传奇' 在数据库中,被嵌套的DQL需要使用()括起来 SELECT name,salary FROM teacher WHERE salary>(SELECT salary FROM teacher WHERE name='范传奇')
-
查看哪些老师的工资是高于平均工资的?
1:未知条件 先查询老师的平均工资是多少? SELECT AVG(salary) FROM teacher 2:查看高于平均工资 SELECT name,salary FROM teacher WHERE salary>(SELECT AVG(salary) FROM teacher)
-
查看和’李费水’在同一个班的学生都有谁?
1:查看李费水的班级号 SELECT class_id FROM student WHERE name='李费水' 2:查看与该人班级号一致的学生 SELECT name,class_id FROM student WHERE class_id=(SELECT class_id FROM student WHERE name='李费水')
-
查看工资最高的老师的工资和奖金是多少?
1:最高的工资是多少? SELECT MAX(salary) FROM teacher 2:查看工资为最高工资老师的信息 SELECT name,salary,comm FROM teacher WHERE salary=(SELECT MAX(salary) FROM teacher)
多行单列子查询
多行单列子查询是可以检索出若干个值。因此作为过滤条件使用时
- 判断等值,要配合:IN,NOT IN使用。等于是不能同时等于好几个值的,只能同于其中之一
- 判断>,>=,<,<=时,要搭配ANY和ALL使用
- >ANY(列表):大于列表其中之一,判断标准:大于列表最小值即可
- >ALL(列表):大于列表所有,判断标准:大于列表最大值
- <ANY(列表):小于最大的即可
- <ALL(列表):小于最小的即可
例
-
查看与"祝雷"和"李费水"在同一个班的学生都有谁?
1:未知条件:"祝雷"和"李费水"的班级号是多少 SELECT class_id FROM student WHERE name IN('祝雷','李费水') 2:查看与他们班级号相同的学生 SELECT name,class_id FROM student WHERE class_id=(SELECT class_id FROM student WHERE name IN('祝雷','李费水'))
错误原因,两个学生的班级号不同,而没有任何一个学生的班级号可以同时等于两个不同的值
SELECT name,class_id FROM student WHERE class_id IN (SELECT class_id FROM student WHERE name IN('祝雷','李费水'))
-
查看比教科目2和科目4老师工资都高的老师都有谁?
1:查看科目2和科目4老师工资都是多少 SELECT salary FROM teacher WHERE subject_id IN (2,4) 2:查看高于他们所有人的工资都有谁? SELECT name,salary,subject_id FROM teacher WHERE salary>ALL(SELECT salary FROM teacher WHERE subject_id IN (2,4)) 另一种思路 SELECT name,salary,subject_id FROM teacher WHERE salary>(SELECT MAX(salary) FROM teacher WHERE subject_id IN(2,4))
在DML语句中使用子查询
例
-
给与’范传奇’负责同一科目的所有老师工资涨500
UPDATE teacher SET salary=salary+500 WHERE subject_id=(SELECT subject_id FROM teacher WHERE name='范传奇')
在DDL语句中使用子查询
可以将一个查询结果集当作一张表创建出来
例
-
创建一张表,该表中记录了每个科目老师的工资情况,要求展示:最高,最低,总和和平均工资以及该科目id
1:查询出对应的数据 SELECT MAX(salary),MIN(salary),SUM(salary),AVG(salary),subject_id FROM teacher GROUP BY subject_id 2:创建表 CREATE TABLE teacher_salary_info( max_salary DOUBLE(8,4), min_salary DOUBLE(8,4), sum_salary DOUBLE(8,4), avg_salary DOUBLE(8,4), subject_id INT ) 3:插入数据 INSERT INTO .... 写若干行 实际写法 CREATE TABLE teacher_salary_info AS SELECT MAX(salary) max_sal,MIN(salary) min_sal, SUM(salary) sum_sal,AVG(salary) avg_sal,subject_id FROM teacher GROUP BY subject_id 当子查询的SELECT子句包含函数或表达式时,应当为其取别名,此时创建的表中该字段名会使用指定的别名
关联查询(重点)
定义
联合多张表查询数据,查询结果集中的字段来自与多张表。
关联关系
表与表中的记录会产生对应关系,用于我们联合查询。
关联关系分类
- 一对一:A表的一条记录仅唯一对应B表中的一条记录
- 一对多:A表中的一条记录对应B表中的多条记录
- 多对多:当A与B表双向看到都是一对多时就是多对多关系
连接条件
在DQL中我们会指定连接条件,用来让数据库在查询中知道两张表中记录与记录的对应关系,从而查询出对应的记录。
关联查询中连接条件通常不可以忽略或缺失,否则会产生笛卡尔积
连接条件的个数:N张表联合查询就要有至少N-1个连接条件
语法
SELECT 字段
FROM 表A,表B[,表C,...]
WHERE A表与B表的连接条件
AND [其他表的连接条件]
AND 过滤条件
注意:连接条件要同时满足,且如果还有过滤条件时,也要与过滤条件同时满足
例
-
查看每个老师以及其负责课程科目名?
SELECT teacher.name,teacher.age,subject.name FROM teacher,subject WHERE teacher.subject_id=subject.id 上述代码缺点:为了区分表中的字段,写法:表名.字段名。 如果表名较长,写起来十分累赘 解决办法:在FROM子句中指定表名时为表取别名。此时区分表字段时可写作:表别名.字段名 SELECT t.name,t.age,s.name FROM teacher t,subject s WHERE t.subject_id=s.id
-
不指定连接条件,会产生笛卡尔积
SELECT t.name,t.age,s.name FROM teacher t,subject s
笛卡尔积的产生
当不指定连接条件时,数据库在进行关联查询时,仍然会用A表一条记录与B表每条记录连接一次,并产生结果集中的一条记录.此时的数据量为A表记录数与B表记录数的乘积.
当表中数据量大时,这样的结果集开销巨大,甚至可能导致服务器宕机.因此要尽量避免.
-
查看班级的名称和对应的班主任(老师)是谁?
1:确定数据来自哪些表,确定FROM子句 class表和teacher表 FROM class c,teacher t 2:当表明确了,就要确定连接条件 班级表中teacher_id的值记录了班主任的id应当对应teacher表的老师id c.teacher_id=t.id SELECT c.name,t.name FROM class c,teacher t WHERE c.teacher_id=t.id
-
查看每个学生的名字,年龄,以及其所在的班级名称和所在楼层
1:确定数据来自哪些表 class表和student表 FROM class c,student s 2:连接条件确定两张表中记录的对应关系 c.id=s.class_id SELECT s.name,s.age,c.name,c.floor FROM class c,student s WHERE c.id=s.class_id
连接条件与过滤条件同时满足
例
-
王克晶是哪个班的班主任?列出:班级名称,楼层,老师名称,工资
1:数据来自哪些表 class c,teacher t 2:连接条件 c.teacher_id=t.id 3:过滤条件 老师的名字是王克晶 SELECT c.name,c.floor,t.name,t.salary FROM class c,teacher t WHERE c.teacher_id=t.id 连接条件 AND t.name='王克晶' 过滤条件 连接条件与过滤条件要同时满足
-
查看三年级的班级班主任都是谁?要列出班级名称,所在楼层,班主任名字和工资
SELECT c.name,c.floor,t.name,t.salary FROM teacher t,class c WHERE t.id=c.teacher_id 连接条件 AND c.name LIKE '3年级%' 过滤条件
-
查看来自南京的学生都有谁?要列出城市名字,学生名字,年龄,性别
SELECT l.name,s.name,s.age,s.gender FROM location l,student s WHERE l.id=s.location_id AND l.name='南京'
-
查看5年级的中队长都有谁?要列出学生名字,年龄,性别,职位和所在班级的名字以及楼层
SELECT s.name,s.age,s.gender,s.job,c.name,c.floor FROM class c,student s WHERE c.id=s.class_id AND c.name LIKE '5年级%' AND s.job='中队长'
N张表关联
N张表关联查询,至少要有N-1个连接条件
例
-
查看"范传奇"所带班级的学生都有谁?要列出:学生名字,年龄,班级名称,老师名字
1:数据来自哪些表 student s,class c,teacher t 2:连接条件 3张表关联至少要有2个连接条件 班级表与学生表的关系:c.id=s.class_id 班级表与老师表的关系:c.teacher_id=t.id 3:过滤条件 老师的名字"范传奇" SELECT s.name,s.age,c.name,t.name FROM student s,class c,teacher t WHERE s.class_id=c.id AND c.teacher_id=t.id AND t.name='范传奇'
-
查看1年级1班的同学的名字和来自的城市
SELECT s.name,l.name,c.name FROM class c,student s,location l WHERE c.id=s.class_id AND s.location_id=l.id AND c.name='1年级1班'
综合练习
题干
1.查看来自北京的学生都是谁?
2.教"英语"的老师都是谁?
3.刘苍松所带班级的学生都有谁?
4.教语文的老师所带的班级有哪些?
5.王克晶所带的班级学生都来自哪些城市(去重)?
6.3年级的几个班主任都教哪些课程?
7.工资高于10000的老师所带班里的大队长都是谁?
8."李费水"的班主任教哪门课?
9.所在4楼的班里的大队长和中队长以及班主任都是谁?
10.全校最小的同学的班主任是谁?
答案
1.查看来自北京的学生都是谁?
SELECT s.name,l.name
FROM student s,location l
WHERE s.location_id=l.id
AND l.name='北京'
2.教"英语"的老师都是谁?
SELECT t.name,su.name
FROM teacher t,subject su
WHERE t.subject_id=su.id
AND su.name='英语'
3.刘苍松所带班级的学生都有谁?
SELECT t.name,c.name,s.name
FROM teacher t,class c,student s
WHERE t.id=c.teacher_id
AND c.id=s.class_id
AND t.name='刘苍松'
4.教语文的老师所带的班级有哪些?
SELECT su.name,t.name,c.name
FROM subject su,teacher t,class c
WHERE su.id=t.subject_id
AND t.id=c.teacher_id
AND su.name='语文'
5.王克晶所带的班级学生都来自哪些城市(去重)?
SELECT DISTINCT l.name
FROM teacher t,class c,student s,location l
WHERE t.id=c.teacher_id
AND c.id=s.class_id
AND l.id=s.location_id
AND t.name='王克晶'
6.3年级的几个班主任都教哪些课程?
SELECT c.name,t.name,su.name
FROM class c,teacher t,subject su
WHERE c.teacher_id=t.id
AND t.subject_id=su.id
AND c.name LIKE '3年级%'
7.工资高于10000的老师所带班里的大队长都是谁?
SELECT t.name,c.name,s.name
FROM teacher t,class c,student s
WHERE t.id=c.teacher_id
AND c.id=s.class_id
AND t.salary>10000
AND s.job='大队长'
8."李费水"的班主任教哪门课?
SELECT s.name,c.name,t.name,su.name
FROM student s,class c,teacher t,subject su
WHERE s.class_id=c.id
AND c.teacher_id=t.id
AND t.subject_id=su.id
AND s.name='李费水'
9.所在4楼的班里的大队长和中队长以及班主任都是谁?
SELECT s.name,s.job,c.name,c.floor,t.name
FROM student s,class c,teacher t
WHERE s.class_id=c.id
AND c.teacher_id=t.id
AND c.floor=4
AND s.job IN('大队长','中队长')
SELECT s.name,s.job,c.name,c.floor,t.name
FROM student s,class c,teacher t
WHERE s.class_id=c.id
AND c.teacher_id=t.id
AND c.floor=4
AND (s.job='大队长' OR s.job='中队长')
10.全校最小的同学的班主任是谁?
SELECT s.name,s.birth,c.name,t.name
FROM student s,class c,teacher t
WHERE s.class_id=c.id
AND c.teacher_id=t.id
AND s.birth=(SELECT MAX(birth) FROM student)
有两个生日最小的,可以去重
SELECT DISTINCT s.name,s.birth,c.name,t.name
FROM student s,class c,teacher t
WHERE s.class_id=c.id
AND c.teacher_id=t.id
AND s.birth=(SELECT MAX(birth) FROM student)
关联查询中使用聚合函数
将关联查询的结果集进行统计
例
-
查看范传奇所带班级的学生共多少人?
1:查询出参与统计的记录 范传奇所带班级的所有学生信息 1.1 数据来自哪些表? FROM teacher t,class c,student s 1.2 连接条件? t.id=c.teacher_id s.class_id=c.id 1.3 过滤条件? t.name='范传奇' SELECT s.name FROM teacher t,class c,student s WHERE t.id=c.teacher_id AND s.class_id=c.id AND t.name='范传奇' 2:在上述查询出参与统计记录的DQL中添加聚合函数 SELECT COUNT(*) FROM teacher t,class c,student s WHERE t.id=c.teacher_id AND s.class_id=c.id AND t.name='范传奇'
-
查看教语文的老师平均工资是多少?
1:查询出参与统计的记录 查询教语文的老师工资是多少? 1.1:数据来自哪些表? FROM subject su,teacher t 1.2:连接条件? t.subject_id=su.id 1.3:过滤条件? su.name='语文' SELECT t.salary FROM subject su,teacher t WHERE t.subject_id=su.id AND su.name='语文' 2:在上述DQL中添加聚合函数 SELECT AVG(t.salary) FROM subject su,teacher t WHERE t.subject_id=su.id AND su.name='语文'
-
查看教每门课老师的平均工资是多少(GROUP BY)?列出平均工资和科目名称
1:查询出参与统计的记录 查询出所有老师的工资,所带科目 1.1:数据来自哪些表? FROM teacher t,subject su 1.2:连接条件? t.subject_id=su.id SELECT t.name,t.salary,su.name FROM teacher t,subject su WHERE t.subject_id=su.id 2:添加分组与聚合函数 SELECT AVG(t.salary),su.name FROM teacher t,subject su WHERE t.subject_id=su.id GROUP BY su.name
-
仅查看平均工资高于6000的那些科目的老师平均工资是多少?列出平均工资和科目名称
SELECT AVG(t.salary),su.name FROM teacher t,subject su WHERE t.subject_id=su.id GROUP BY su.name HAVING AVG(salary)>6000
-
查看工资最高的老师班里的学生共多少人?
1:未知条件? 最高工资是多少 确定子查询 SELECT MAX(salary) FROM teacher 2:查询参与统计的记录 查询最高工资老师所带班的学生都有谁 2.1:数据来自哪些表 FROM teacher t,class c,student s 2.2:连接条件 t.id=c.teacher_id s.class_id=c.id 2.3:过滤条件:该老师的工资等于最高工资 t.salary=(SELECT MAX(salary) FROM teacher) SELECT t.salary,t.name,c.name,s.name FROM teacher t,class c,student s WHERE t.id=c.teacher_id AND s.class_id=c.id AND t.salary=(SELECT MAX(salary) FROM teacher) 3:在上述DQL上加聚合函数 SELECT COUNT(*) FROM teacher t,class c,student s WHERE t.id=c.teacher_id AND s.class_id=c.id AND t.salary=(SELECT MAX(salary) FROM teacher)
综合练习
题干
1:教语文的老师所带班级各多少学生?
2:每门课的老师所带班级各多少学生?
3:来自上海的学生的班主任都有谁?
4:来自南京的学生共多少人
5:来自武汉的男同学和女同学分别多少人?
6:每个城市的学生各多少人
7:高于平均工资的老师所带的班级分别多少学生?
8:每个老师班里各多少来自郑州的学生?
答案
1:教语文的老师所带班级各多少学生?
2:每门课的老师所带班级各多少学生?
3:来自上海的学生的班主任都有谁?
4:来自南京的学生共多少人
5:来自武汉的男同学和女同学分别多少人?
6:每个城市的学生各多少人
7:高于平均工资的老师所带的班级分别多少学生?
8:每个老师班里各多少来自郑州的学生?