目录
1. 表的设计
2. 查询与新增的联合
3. 聚合查询
3.1 聚合查询函数
3.1.1 COUNT函数
3.1.2 SUM函数
3.1.3 AVG 函数
3.1.4 MIN函数 与 MAX函数
3.2 GROUP BY子句
3.3 HAVING
(一)、梳理清楚需求中的“实体”:
(1)数据库中的实体类比面向对象的对象;
(2)很多时候每个实体都需要对应一张表来表示;
(二)、梳理清楚实体之间的关系:
(1)一对一:如学生与账号的关系:
第一种设计方式:一个大表包含学生信息+账号信息;
account_student(accountId,username,password,studentName...);
第二种设计方式:两个表相互关联:账户表+学生信息表;
account(accountId,userName,password,studentId);
student(studentId,studentName...);
将账户表通过studentId这一列与学生信息表联系起来了;
第三种设计方式:
account(accountId,userName,password);
student(studentId, studentName,accountId);
这种方式使用最多,后续教师表也可与account表关联;
(2)一对多:如班级与学生的关系:
第一种设计方式:使用数组或列表保存一个表的信息(但MySQL不存在数组类型,不允许这种设计方式,但有些数据库如Redis存在数组类型,就可以考虑这种设计方式)
student(studentId,studentName);
class(classId,className,studentIdList);
第二种设计方式:(最典型的一对多设计方式)
class(classId,className);
student(studentId,name,classId);
(3)多对多:如学生与课程的关系
设计方式:学生表+课程表+关联表:
student(studentId,studentName);
course(courseId,courseName);
student_course(studentId,courseId);
(三)、按照不同的关系代入既定公式;
注:一般只要实体和关系明确了,表的设计也基本成型。如果实体较多关系较复杂,可以画一个“实体关系图”(ER图)来表示;
查询与新增的联合即:将查询结果作为新增的数据;
现有student表如下(student2表为空):
mysql> select* from student;
+------+------+
| id | name |
+------+------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
+------+------+
3 rows in set (0.00 sec)
先将student表的数据新增至student2表中:
mysql> insert into student2 select* from student;
Query OK, 3 rows affected (0.10 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select* from student2;
+------+------+
| id | name |
+------+------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
+------+------+
3 rows in set (0.00 sec)
注:(1)查询与新增联合的要求是:查询结果的列数和类型与插入表的列数和类型匹配;
聚合查询即:查询过程中,表的行与行之间进行一定的运算;
(表达式查询是在查询过程中,表的列与列之间进行一定运算)
聚合查询函数时SQL提供的库函数:
函数 | 说明 |
COUNT ( [ DISTINCT ] ) expr ) | 返回查询到数据的数量 |
SUM ( [ DISTINCT ] ) expr ) | 返回查询到数据的总和,不是数字没有意义 |
AVG ( [ DISTINCT ] ) expr ) | 返回查询到数据的平均值,不是数字没有意义 |
MAX ( [ DISTINCT ] ) expr ) | 返回查询到数据的最大值,不是数字没有意义 |
MIN ( [ DISTINCT ] ) expr ) | 返回查询到数据的最小值,不是数字没有意义 |
基于以下student表:
mysql> select* from student;
+------+------+
| id | name |
+------+------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
| 4 | NULL |
+------+------+
4 rows in set (0.00 sec)
使用聚合函数count分别查询表格总行数,id列行数和name列行数:
mysql> select count(*) from student;
+----------+
| count(*) |
+----------+
| 4 |
+----------+
1 row in set (0.00 sec)
mysql> select count(id) from student;
+-----------+
| count(id) |
+-----------+
| 4 |
+-----------+
1 row in set (0.00 sec)
mysql> select count(name) from student;
+-------------+
| count(name) |
+-------------+
| 3 |
+-------------+
1 row in set (0.00 sec)
注:(1)NULL作为空值,在使用count(*)进行查询是是可以被计数的,但是使用count(列名)就不会被计数;
基于以下exam_result表:
mysql> select* from exam_result;
+------+--------+---------+------+---------+
| id | name | chinese | math | english |
+------+--------+---------+------+---------+
| 1 | 唐三藏 | 67.0 | 98.0 | 56.0 |
| 2 | 孙悟空 | 87.5 | 78.0 | 77.0 |
| 3 | 猪悟能 | 88.0 | 98.5 | 90.0 |
| 4 | 曹孟德 | 82.0 | 84.0 | 67.0 |
| 5 | 刘玄德 | 55.5 | 85.0 | 45.0 |
| 6 | 孙权 | 70.0 | 73.0 | 78.5 |
| 7 | 宋公明 | 75.0 | 65.0 | 30.0 |
+------+--------+---------+------+---------+
7 rows in set (0.00 sec)
使用聚合函数SUM计算语文成绩总和:
mysql> select sum(chinese) from exam_result;
+--------------+
| sum(chinese) |
+--------------+
| 525.0 |
+--------------+
1 row in set (0.00 sec)
注:(1)sum函数名与其后的括号之间不能有空格,否则会报错;
(2)前文提过:NULL与其他数据计算结果仍为NULL,但SUM函数会自动跳过结果为NULL的和,对结果不构成影响;
(3)聚合函数SUM只对数字加和有效,对字符串类型无效,结果为0;
仍基于上文exam_result表,使用聚合函数AVG查询语文成绩与总分平均分:
mysql> select sum(chinese) from exam_result;
+--------------+
| sum(chinese) |
+--------------+
| 525.0 |
+--------------+
1 row in set (0.00 sec)
mysql> select avg(chinese+math+english)as avgTotal from exam_result;
+-----------+
| avgTotal |
+-----------+
| 221.42857 |
+-----------+
1 row in set (0.00 sec)
仍基于以上exam_result表,使用聚合函数MAX和MIN查询最高和最低语文成绩:
mysql> select max(chinese),min(chinese) from exam_result;
+--------------+--------------+
| max(chinese) | min(chinese) |
+--------------+--------------+
| 88.0 | 55.5 |
+--------------+--------------+
1 row in set (0.00 sec)
基于以下emp表:
mysql> select* from emp;
+------+------+--------+--------+
| id | name | role | salary |
+------+------+--------+--------+
| 1 | 张三 | 讲师 | 10000 |
| 2 | 李四 | 讲师 | 11000 |
| 3 | 王五 | 讲师 | 12000 |
| 4 | 赵六 | 学管师 | 10000 |
| 5 | 田七 | 学管师 | 9000 |
| 6 | 钱八 | 老板 | 100000 |
| 7 | 陈九 | 老板 | 120000 |
+------+------+--------+--------+
7 rows in set (0.00 sec)
求每个岗位的平均薪资,就要使用到分组查询:
mysql> select role, avg(salary) from emp group by role;
+--------+-------------+
| role | avg(salary) |
+--------+-------------+
| 讲师 | 11000.0000 |
| 学管师 | 9500.0000 |
| 老板 | 110000.0000 |
+--------+-------------+
3 rows in set (0.00 sec)
注:(1)指定一个列,就会把列里的值相同的分到一个组中;
(2)select 指定的列要么是带有聚合函数的,要么就是得指定的group by的列,不能指定一个非聚合、非group by的列;
分组时可以指定条件筛选:
第一种:分组前筛选:使用where条件:
计算各个岗位(讲师除过张三外的)平均薪资:
mysql> select role,avg(salary) from emp where name!="张三" group by role;
+--------+-------------+
| role | avg(salary) |
+--------+-------------+
| 讲师 | 11500.0000 |
| 学管师 | 9500.0000 |
| 老板 | 110000.0000 |
+--------+-------------+
3 rows in set (0.00 sec)
第二种:分组后筛选:使用having条件:
计算除过老板的其余岗位的平均薪资:
mysql> select role,avg(salary) from emp group by role having role!="老板";
+--------+-------------+
| role | avg(salary) |
+--------+-------------+
| 讲师 | 11000.0000 |
| 学管师 | 9500.0000 |
+--------+-------------+
2 rows in set (0.00 sec)
第三种:同时在分组前和分组后进行筛选:
计算除过老板岗位,不包括张三在内的所有岗位的平均薪资:
mysql> select role,avg(salary) from emp where name!="张三" group by role having role!="老板";
+--------+-------------+
| role | avg(salary) |
+--------+-------------+
| 讲师 | 11500.0000 |
| 学管师 | 9500.0000 |
+--------+-------------+
2 rows in set (0.00 sec)