MySQL(四)复合查询与联合查询


复合查询

复合函数

通常对于统计数量,计算平均值,寻找最大值等操作,都可以通过复合函数来完成
MySQL给出了以下五种聚合函数

  • AVG(): 返回查询到的数据的平均值
  • COUNT():返回查询到的数据的数量
  • SUM():返回查询到的数据的总和
  • MAX():返回查询到的数据的最大值
  • MIN():返回查询到的数据的最小值

注意:复合函数仅能作用于数字


下面对这个表进行案例演示

+----+------+--------+------------+-------+---------+
| id | age  | name   | birth      | math  | english |
+----+------+--------+------------+-------+---------+
|  1 |   11 | 李华   | 2020-08-12 | 76.50 |   87.50 |
|  2 |   15 | 李梅   | 2020-08-13 | 88.50 |   90.50 |
|  3 |   18 | 张三   | 2020-08-14 | 84.50 |   70.50 |
|  4 |   16 | 李四   | 2020-08-15 | 75.60 |   40.80 |
|  5 |   14 | 王五   | 2020-08-16 | 48.80 |   91.90 |
|  6 |   13 | 马六   | 2020-08-17 | 85.90 |   95.40 |
+----+------+--------+------------+-------+---------+

AVG

返回查询到的数据的平均值

//计算平均数学成绩
SELECT AVG(math) FROM student; 


+-----------+
| AVG(math) |
+-----------+
| 76.633333 |
+-----------+

COUNT

返回查询到的数据的数量

//统计班级中有多少个学生
SELECT COUNT(*) FROM student; 

+----------+
| COUNT(*) |
+----------+
|        6 |
+----------+

SUM

返回查询到的数据的总和

//计算班上学生的年龄总和
SELECT SUM(age) FROM student; 

+----------+
| SUM(age) |
+----------+
|       87 |
+----------+

MAX

返回查询到的数据的最大值

//找出英语最高分
SELECT MAX(english) FROM student; 
+--------------+
| MAX(english) |
+--------------+
|        95.40 |
+--------------+

MIN

返回查询到的数据的最小值

//找出总分最低的
SELECT MIN(english + math) AS TOTAL FROM student; 

+--------+
| TOTAL  |
+--------+
| 116.40 |
+--------+

分组查询

分组查询即使用GROUP BY子句对指定列进行分组查询

注意:SELECT指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中。

GROUP BY

语法

SELECT 查询项 FROM 表名 GROUP BY 分组依据;
//建立一个职员表
create table emp( 
 id int primary key auto_increment comment '工号', 
 name varchar(20) not null comment '职员姓名', 
 role varchar(20) not null comment '职位', 
 salary numeric(11,2) comment '月薪' 
); 

//插入一些数据
insert into emp(name, role, salary) values 
('李华','实习生', 2500.20), 
('李梅','普通职员', 7000.99), 
('张三','普通职员', 6000.11), 
('李四','普通职员', 5833.5), 
('王五','实习生', 2700.33), 
('马六','经理', 12000.66);

接下来按照职位进行分组,查询各职位的平均月薪、最高月薪和最低月薪

select role,max(salary),min(salary),avg(salary) from emp group by role;

+--------------+-------------+-------------+--------------+
| role         | max(salary) | min(salary) | avg(salary)  |
+--------------+-------------+-------------+--------------+
| 实习生       |     2700.33 |     2500.20 |  2600.265000 |
| 普通职员     |     7000.99 |     5833.50 |  6278.200000 |
| 经理         |    12000.66 |    12000.66 | 12000.660000 |
+--------------+-------------+-------------+--------------+

HAVING

如果使用GROUP BY进行分组,如果需要使用条件判断来过滤数据,就不能再使用WHERE,而是要使用HAVING
语法

SELECT 查询项 FROM 表名 GROUP BY 分组依据 HAVING 条件;
//查询平均工资超过5000元的职位
select role,max(salary),min(salary),avg(salary) 
from emp 
group by role 
having avg(salary) > 5000;

+--------------+-------------+-------------+--------------+
| role         | max(salary) | min(salary) | avg(salary)  |
+--------------+-------------+-------------+--------------+
| 普通职员     |     7000.99 |     5833.50 |  6278.200000 |
| 经理         |    12000.66 |    12000.66 | 12000.660000 |
+--------------+-------------+-------------+--------------+

联合查询

为了方便用例,首先建立学生表、班级表、课程表、成绩表

DROP TABLE IF EXISTS course;
CREATE TABLE course(
	id int PRIMARY KEY AUTO_INCREMENT,
	name varchar(8)
);

DROP TABLE IF EXISTS classes;
CREATE TABLE classes (
 id INT PRIMARY KEY auto_increment,
 name VARCHAR(20),
 `desc` VARCHAR(100)
);

DROP TABLE IF EXISTS student;
CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT, 
	sn INT UNIQUE,
	name VARCHAR(20) DEFAULT 'unkown',
	qq_mail VARCHAR(20),
	classes_id INT,
	FOREIGN KEY (classes_id) REFERENCES classes(id)
);

DROP TABLE IF EXISTS score;
CREATE TABLE score (
	id INT PRIMARY KEY auto_increment,
 	score DECIMAL(3, 1),
	student_id int,
	course_id int,
	FOREIGN KEY (student_id) REFERENCES student(id),
	FOREIGN KEY (course_id) REFERENCES course(id)
);

内连接

内连接即查找两个表中的交集,找到两个表中同时符合条件的数据,进行连接。
语法

select 字段 from1 别名1 [inner] join2 别名2 on 连接条件 and 其他条件; 
select 字段 from1 别名1,2 别名2 where 连接条件 and 其他条件; 
//查找名为白素贞的学生的成绩
select 
stu.name, sco.score 
from  
student stu inner join score sco 
on 
stu.id = sco.id and stu.name = "白素贞";

+-----------+-------+
| name      | score |
+-----------+-------+
| 白素贞    |  33.0 |
+-----------+-------+

//使用另外一个语法
select 
stu.name, sco.score 
from  
student stu, score sco 
where
stu.id = sco.id and stu.name = "白素贞";

+-----------+-------+
| name      | score |
+-----------+-------+
| 白素贞    |  33.0 |
+-----------+-------+

外连接

外连接又分左外连接和右外连接
简单来说就是,如果左边的表完全显示就是左连接,右边的表完全显示就是右连接

左连接

对于左连接,以左表的数据为基准,在右表中查找符合条件的数据,找不到的以也会NULL展示。
语法

select 字段名 from 表名1 left join 表名2 on 连接条件; 

示例

//左连接,以学生表为基准,查找成绩表中所有学生的成绩
select * from student stu left join score sco on stu.id=sco.student_id;

```sql
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
| id | sn    | name            | qq_mail          | classes_id | id   | score | student_id | course_id |
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    1 |  70.5 |          1 |         1 |
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    2 |  98.5 |          1 |         3 |
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    3 |  33.0 |          1 |         5 |
|  1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com  |          1 |    4 |  98.0 |          1 |         6 |
|  2 |   835 | 菩提老祖        | NULL             |          1 |    5 |  60.0 |          2 |         1 |
|  2 |   835 | 菩提老祖        | NULL             |          1 |    6 |  59.5 |          2 |         5 |
|  3 |   391 | 白素贞          | NULL             |          1 |    7 |  33.0 |          3 |         1 |
|  3 |   391 | 白素贞          | NULL             |          1 |    8 |  68.0 |          3 |         3 |
|  3 |   391 | 白素贞          | NULL             |          1 |    9 |  99.0 |          3 |         5 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   10 |  67.0 |          4 |         1 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   11 |  23.0 |          4 |         3 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   12 |  56.0 |          4 |         5 |
|  4 |    31 | 许仙            | xuxian@qq.com    |          1 |   13 |  72.0 |          4 |         6 |
|  5 |    54 | 不想毕业        | NULL             |          1 |   14 |  81.0 |          5 |         1 |
|  5 |    54 | 不想毕业        | NULL             |          1 |   15 |  37.0 |          5 |         5 |
|  6 | 51234 | 好好说话        | say@qq.com       |          2 |   16 |  56.0 |          6 |         2 |
|  6 | 51234 | 好好说话        | say@qq.com       |          2 |   17 |  43.0 |          6 |         4 |
|  6 | 51234 | 好好说话        | say@qq.com       |          2 |   18 |  79.0 |          6 |         6 |
|  7 | 83223 | tellme          | NULL             |          2 |   19 |  80.0 |          7 |         2 |
|  7 | 83223 | tellme          | NULL             |          2 |   20 |  92.0 |          7 |         6 |
|  8 |  9527 | 老外学中文      | foreigner@qq.com |          2 | NULL |  NULL |       NULL |      NULL |
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+

可以看到,此时进行左连接,以学生表为基准在成绩表中查找,所以对于成绩表中不存在的学生,会用NULL表示而不是直接忽略

右连接

对于右连接,以右表的数据为基准,在左表中查找符合条件的数据,找不到的以也会NULL展示。
语法

语法

select 字段 from 表名1 right join 表名2 on 连接条件; 

示例

//右连接,以成绩表为基准,查找学生表中有成绩的学生
select * from student stu right join score sco on stu.id=sco.student_id;

+------+-------+-----------------+-----------------+------------+----+-------+------------+-----------+
| id   | sn    | name            | qq_mail         | classes_id | id | score | student_id | course_id |
+------+-------+-----------------+-----------------+------------+----+-------+------------+-----------+
|    1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com |          1 |  1 |  70.5 |          1 |         1 |
|    1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com |          1 |  2 |  98.5 |          1 |         3 |
|    1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com |          1 |  3 |  33.0 |          1 |         5 |
|    1 |  9982 | 黑旋风李逵      | xuanfeng@qq.com |          1 |  4 |  98.0 |          1 |         6 |
|    2 |   835 | 菩提老祖        | NULL            |          1 |  5 |  60.0 |          2 |         1 |
|    2 |   835 | 菩提老祖        | NULL            |          1 |  6 |  59.5 |          2 |         5 |
|    3 |   391 | 白素贞          | NULL            |          1 |  7 |  33.0 |          3 |         1 |
|    3 |   391 | 白素贞          | NULL            |          1 |  8 |  68.0 |          3 |         3 |
|    3 |   391 | 白素贞          | NULL            |          1 |  9 |  99.0 |          3 |         5 |
|    4 |    31 | 许仙            | xuxian@qq.com   |          1 | 10 |  67.0 |          4 |         1 |
|    4 |    31 | 许仙            | xuxian@qq.com   |          1 | 11 |  23.0 |          4 |         3 |
|    4 |    31 | 许仙            | xuxian@qq.com   |          1 | 12 |  56.0 |          4 |         5 |
|    4 |    31 | 许仙            | xuxian@qq.com   |          1 | 13 |  72.0 |          4 |         6 |
|    5 |    54 | 不想毕业        | NULL            |          1 | 14 |  81.0 |          5 |         1 |
|    5 |    54 | 不想毕业        | NULL            |          1 | 15 |  37.0 |          5 |         5 |
|    6 | 51234 | 好好说话        | say@qq.com      |          2 | 16 |  56.0 |          6 |         2 |
|    6 | 51234 | 好好说话        | say@qq.com      |          2 | 17 |  43.0 |          6 |         4 |
|    6 | 51234 | 好好说话        | say@qq.com      |          2 | 18 |  79.0 |          6 |         6 |
|    7 | 83223 | tellme          | NULL            |          2 | 19 |  80.0 |          7 |         2 |
|    7 | 83223 | tellme          | NULL            |          2 | 20 |  92.0 |          7 |         6 |
+------+-------+-----------------+-----------------+------------+----+-------+------------+-----------+

可以看到,此时进行右连接,以成绩表为基准在学生表中查找,所以对于学生表中不存在的学生,会用NULL表示而不是直接忽略


自连接

自连接即将自己的表进行连接,需要对表名进行别名显示

例如要查询本班中所有JAVA成绩比计算机原理成绩高的成绩信息

//join on语句
select * 
from 
score s1 join score s2
on
s1.student_id = s2.student_id
and s1.score > s2.score
and s1.id = 1
and s2.id = 3;

//where语句
select * 
from
score s1,score s2
where
s1.student_id = s2.student_id
and s1.score > s2.score
and s1.id = 1
and s2.id = 3;

+----+-------+------------+-----------+----+-------+------------+-----------+
| id | score | student_id | course_id | id | score | student_id | course_id |
+----+-------+------------+-----------+----+-------+------------+-----------+
|  1 |  70.5 |          1 |         1 |  3 |  33.0 |          1 |         5 |
+----+-------+------------+-----------+----+-------+------------+-----------+


子查询

子查询又叫做嵌套查询,其实就是嵌入其他sql语句中的select语句,一般用于查询的条件是另一条语句的结果这一情况。

例如

//单行子查询,查找与白素贞同班的同学。即查询到白素贞所在的班号,再通过班号查询该班学生
select * from student where classes_id=
(select classes_id from student where name='白素贞');

+----+------+-----------------+-----------------+------------+
| id | sn   | name            | qq_mail         | classes_id |
+----+------+-----------------+-----------------+------------+
|  1 | 9982 | 黑旋风李逵      | xuanfeng@qq.com |          1 |
|  2 |  835 | 菩提老祖        | NULL            |          1 |
|  3 |  391 | 白素贞          | NULL            |          1 |
|  4 |   31 | 许仙            | xuxian@qq.com   |          1 |
|  5 |   54 | 不想毕业        | NULL            |          1 |
+----+------+-----------------+-----------------+------------+

//多行子查询,查询java和英语的成绩信息。即先查询到java和英语的课程号,再通过课程号查询成绩表
select * from score where course_id in 
(select id from course where name='java' or name='英文');

合并查询

UNION

该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行
语法

结果集A
UNION
结果集B;

例如

//查找id小于2或者名字叫做语文和英语的课程
SELECT * FROM course WHERE id < 3 
UNION
SELECT * FROM course WHERE name in ("语文", "英文");

+----+--------------------+
| id | name               |
+----+--------------------+
|  1 | Java               |
|  2 | 中国传统文化       |
|  4 | 语文               |
|  6 | 英文               |
+----+--------------------+

同样的结果也可以通过or语句来得到

SELECT * FROM course WHERE id < 2 OR name in ("语文", "英文");

+----+--------+
| id | name   |
+----+--------+
|  1 | Java   |
|  4 | 语文   |
|  6 | 英文   |
+----+--------+

但是OR这个逻辑运算符会忽略索引,所以会导致在海量数据查询中性能会下降很多。


UNION ALL

该操作符用于取得两个结果集的并集。当使用该操作符时,不自动去掉结果集中的重复行
与上面的使用相同,但是不会去掉重复数据

SELECT * FROM course WHERE id < 3
UNION ALL
SELECT * FROM course WHERE name = "英文";
+----+--------------------+
| id | name               |
+----+--------------------+
|  1 | Java               |
|  2 | 中国传统文化        |
|  6 | 英文               |
| 10 | 英文               |
+----+--------------------+

猜你喜欢

转载自blog.csdn.net/qq_35423154/article/details/108011200