一:复合查询
通常对于统计数量,计算平均值,寻找最大值等操作,都可以通过复合函数来完成 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 中则必须包含在聚合函数中。
//建立一个职员表
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);
GROUP BY:
SELECT 查询项 FROM 表名 GROUP BY 分组依据;
按照职位进行分组,查询各职位的平均月薪、最高月薪和最低月薪:
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 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名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;
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
| 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 | 英文 |
+----+--------------------+
与上面的使用相同,但是不会去掉重复数据