目录

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. 表的设计

(一)、梳理清楚需求中的“实体”:

(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图)来表示;

2. 查询与新增的联合

查询与新增的联合即:将查询结果作为新增的数据;

现有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)查询与新增联合的要求是:查询结果的列数和类型与插入表的列数和类型匹配

3. 聚合查询

聚合查询即:查询过程中,表的行与行之间进行一定的运算

表达式查询是在查询过程中,表的列与列之间进行一定运算)

3.1 聚合查询函数

聚合查询函数时SQL提供的库函数:

函数

说明

COUNT ( [ DISTINCT ] ) expr )

返回查询到数据的数量

SUM ( [ DISTINCT ] ) expr )

返回查询到数据的总和,不是数字没有意义

AVG ( [ DISTINCT ] ) expr )

返回查询到数据的平均值,不是数字没有意义

MAX ( [ DISTINCT ] ) expr )

返回查询到数据的最大值,不是数字没有意义

MIN ( [ DISTINCT ] ) expr )

返回查询到数据的最小值,不是数字没有意义

3.1.1  COUNT函数

 基于以下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(列名)就不会被计数;

3.1.2 SUM函数

基于以下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;

3.1.3 AVG 函数

仍基于上文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)

 3.1.4 MIN函数 与 MAX函数

仍基于以上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)

3.2 GROUP BY子句

基于以下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的列;

3.3 HAVING 

分组时可以指定条件筛选:

第一种:分组前筛选:使用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)