## 测试数据

```sql
/*stu测试数据*/
create table stu
(
    stuNo char(6) primary key,
    stuName varchar(10) not null,
    stuSex char(2) not null,
    stuAge tinyint not null ,
    stuSeat tinyint not null,
    stuAddress varchar(10) not null,
    ch tinyint,
    math tinyint 
);


insert into stu values ('s25301','张秋丽','男',18,1,'北京',80,null);
insert into stu values ('s25302','李文才','男',31,3,'上海',77,76);
insert into stu values ('s25303','李斯文','女',22,2,'北京',55,82);
insert into stu values ('s25304','欧阳俊雄','男',28,4,'天津',null,74);
insert into stu values ('s25305','诸葛丽丽','女',23,7,'河南',72,56);
insert into stu values ('s25318','争青小子','男',26,6,'天津',86,92);
insert into stu values ('s25319','梅超风','女',23,5,'河北',74,67);

insert into stu values ('s25320','Tom','男',24,8,'北京',65,67);
insert into stu values ('s25321','Tabm','女',23,9,'河北',88,77);

/*stuinfo测试数据*/
create table stuinfo
(
    stuNo char(6) primary key,
    stuName varchar(10) not null,
    stuSex char(2) not null,
    stuAge tinyint not null ,
    stuSeat tinyint not null,
    stuAddress varchar(10) not null
);


insert into stuinfo values ('s25301','张秋丽','男',18,1,'北京');
insert into stuinfo values ('s25302','李文才','男',31,3,'上海');
insert into stuinfo values ('s25303','李斯文','女',22,2,'北京');
insert into stuinfo values ('s25304','欧阳俊雄','男',28,4,'天津');
insert into stuinfo values ('s25305','诸葛丽丽','女',23,7,'河南');
insert into stuinfo values ('s25318','争青小子','男',26,6,'天津');
insert into stuinfo values ('s25319','梅超风','女',23,5,'河北');

/*stuMarks测试数据*/

create table stuMarks
(
examNo char(7) primary key,
stuNo char(6) not null ,
writtenExam int,
labExam int
);

insert into stumarks values ('s271811','s25303',80,58);
insert into stumarks values ('s271813','s25302',50,90);
insert into stumarks values ('s271815','s25304',65,50);
insert into stumarks values ('s271816','s25301',77,82);
insert into stumarks values ('s271819','s25318',56,48);
insert into stumarks values ('s271820','s25320',66,77);
```

## 1.1 今日目标

1. 理解实体之间的关系
2. 理解绘制E-R图
3. 理解三范式
4. 理解范式和性能的关系
5. 能够查询表中的数据
6. 理解聚合函数
7. 理解模糊查询
8. 理解分组查询

## 1.2  数据库基本概念

1、关系:两个表的公共字段

2、行:也称记录,也称实体

3、列:也称字段,也称属性

```
就表结构而言,表分为行和列;
就表数据而言,分为记录和字段;
就面向对象而言,一个记录就是一个实体,一个字段就是一个属性。
```

4、数据冗余:相同的数据存储在不同的地方

```
脚下留心:
1、冗余只能减少,不能杜绝。
2、减少冗余的方法是分表
3、为减少数据查找的麻烦,允许数据有一定的冗余
```

5、数据完整性:正确性+准确性=数据完整性

```
正确性:数据类型正确
准确性:数据范围要准确
```

思考:学生的年龄是整型,输入1000岁,正确性和准确性如何?

答:正确的,但不准确

思考:年龄是整形的,收入了字符串,正确性和准确性如何?

答:不正确

 

## 1.3  实体和实体之间的关系

1、一对一

2、一对多 (多对一)

3、多对多 ![1536975724695](https://yp.smallkun.cn/markdown/1536975724695.png!compress!compress)



#### 1.3.1 一对多 1:N

1、主表中的一条记录对应从表中的多条记录。

2、一对多和多对一是一样的

 ![1536976096582](https://yp.smallkun.cn/markdown/1536976096582.png!compress!compress)

如何实现一对多?

答:主键和非主键建关系

问题:说出几个一对多的关系?

答:班级表和学生表、      班主表和学生表



#### 1.3.2   一对一(1:1)

1、主表中的一条记录对应从表中的一条记录

  ![1536976513236](https://yp.smallkun.cn/markdown/1536976513236.png!compress!compress)

如何实现一对一?

主键和主键建关系就能实现一对一。

```
思考:一对一两个表完全可以用一个表实现,为什么还要分成两个表?

答:在字段数量很多情况下,数据量也就很大,每次查询都需要检索大量数据,这样效率低下。我们可以将所有字段分成两个部分,“常用字段”和“不常用字段”,这样对大部分查询者来说效率提高了。【表的垂直分割】
```



#### 1.3.3   多对多(N:M)

主表中的一条记录对应从表中的多条记录,从表中的一条记录对应主表中的多条记录

班级和讲师的关系

 ![1536977577667](https://yp.smallkun.cn/markdown/1536977577667.png!compress!compress)



如何实现多对多?

答:建立第三张表来保存关系。

问题:说出几个多对多的关系?

1、科目表和学生表的关系		2、商品表和订单表         3、游戏目录表和玩家表



## 1.4 数据库设计的步骤

  ![1536977906540](https://yp.smallkun.cn/markdown/1536977906540.png!compress!compress)



#### 1.4.1   数据库设计具体步骤

1、     收集信息:与该系统有关人员进行交流、坐谈,充分理解数据库需要完成的任务

2、     标识对象(实体-Entity)标识数据库要管理的关键对象或实体 

3、     标识每个实体的属性(Attribute)

4、     标识对象之间的关系(Relationship)

5、     将模型转换成数据库

6、     规范化

#### 1.4.2   绘制E-R图

  E-R(Entity-Relationship)实体关系图 

E-R图的语法

 ![1536978470142](https://yp.smallkun.cn/markdown/1536978470142.png!compress!compress)

绘制E-R图

 ![1536978565499](https://yp.smallkun.cn/markdown/1536978565499.png!compress!compress)

 

#### 1.4.3   将E-R图转成表

1、     实体转成表,属性转成字段

2、     如果没有合适的字段做主键,给表添加一个自动增长列做主键。



#### 1.4.4  例题

1、项目需求

```
BBS论坛的基本功能:
用户注册和登录,后台数据库需要存放用户的注册信息和在线状态信息;
用户发贴,后台数据库需要存放贴子相关信息,如贴子内容、标题等;
用户可以对发帖进行回复;
论坛版块管理:后台数据库需要存放各个版块信息,如版主、版块名称、贴子数等;
```

2、标识对象

```
参与的对象有:用户、发的帖子、跟帖、板块
```

3、标识对象的属性

 ![1536978271446](https://yp.smallkun.cn/markdown/1536978271446.png!compress!compress)

4、建立关系,绘制E-R图

 ![1536978734804](https://yp.smallkun.cn/markdown/1536978734804.png!compress!compress)

5、将E-R图转出表结构



## 1.5 数据规范化

Codd博士定义了6个范式来规范化数据库,范式由小到大来约束,范式越高冗余越小,但表的个数也越多。实验证明,三范式是性价比最高的。 

#### 1.5.1   第一范式:确保每列原子性

第一范式确保每个字段不可再分

  ![1536979522448](https://yp.smallkun.cn/markdown/1536979522448.png!compress!compress)

思考:如下表设计是否合理?

 ![1536979672041](https://yp.smallkun.cn/markdown/1536979672041.png!compress!compress)

不合理。不满足第一范式,上课时间可以再分

 ![1536979718323](https://yp.smallkun.cn/markdown/1536979718323.png!compress!compress)



思考:地址包含省、市、县、地区是否需要拆分?

答:如果仅仅起地址的作用,不需要统计,可以不拆分;如果有按地区统计的功能需要拆分。

在实际项目中,建议拆分。

 

#### 1.5.2   第二范式:非键字段必须依赖于键字段

一个表只能描述一件事

  ![1536980482113](https://yp.smallkun.cn/markdown/1536980482113.png!compress!compress)

思考:如下表设计是否合理?

 ![1536980574792](https://yp.smallkun.cn/markdown/1536980574792.png!compress)



#### 1.5.3   第三范式:消除传递依赖

在所有的非键字段中,不能有传递依赖

  ![1536981861980](https://yp.smallkun.cn/markdown/1536981861980.png!compress!compress)

下列设计是否满足第三范式?

  ![1536982061259](https://yp.smallkun.cn/markdown/1536982061259.png!compress!compress)

不满足,因为语文和数学确定了,总分就确定了。

```
多学一招:上面的设计不满足第三范式,但是高考分数表就是这样设计的,为什么?

答:高考分数峰值访问量非常大,这时候就是性能更重要。当性能和规范化冲突的时候,我们首选性能。这就是“反三范式”。
```

#### 1.5.4  数据库设计的例题

1、需求

```
公司承担多个工程项目,每一项工程有:工程号、工程名称、施工人员等
公司有多名职工,每一名职工有:职工号、姓名、性别、职务(工程师、技术员)等
公司按照工时和小时工资率支付工资,小时工资率由职工的职务决定(例如,技术员的小时工资率与工程师不同)
```

2、工资表

 ![1536982976983](https://yp.smallkun.cn/markdown/1536982976983.png!compress!compress)

3、将工资表转成数据库表

 ![1536983011535](https://yp.smallkun.cn/markdown/1536983011535.png!compress!compress)

4、这个表存在的问题

```
A:新人入职需要虚拟一个项目

B:职务更改,小时工资率可能会忘记更改,造成数据不完整

C:有人离职,删除记录后,工程也没有了
```

5、规范化表

```
第一步:这个表满足第一范式

第二步:这个表不是描述了一件事情
```

 ![1536983332419](https://yp.smallkun.cn/markdown/1536983332419.png!compress!compress)



```
第三步:是否满足第三范式
```

 ![1536983422611](https://yp.smallkun.cn/markdown/1536983422611.png!compress!compress)

更改如下:

 ![1536983406042](https://yp.smallkun.cn/markdown/1536983406042.png!compress!compress)

 

## 1.6 查询语句

```sql
语法:select [选项] 列名 [from 表名] [where 条件]  [group by 分组] [order by 排序][having 条件] [limit 限制]
```

#### 1.6.1   字段表达式

```sql
mysql> select '锄禾日当午';
+------------+
| 锄禾日当午          |
+------------+
| 锄禾日当午          |
+------------+

mysql> select 10*10;
+-------+
| 10*10 |
+-------+
|   100 |
+-------+
```

通过as给字段取别名

```sql
mysql>  select '锄禾日当午' as content;
+------------+
| content    |
+------------+
| 锄禾日当午          |
+------------+
1 row in set (0.00 sec)

mysql> select 10*10 as result;
+--------+
| result |
+--------+
|    100 |
+--------+
1 row in set (0.00 sec)
```

多学一招:as可以省略

```sql
mysql> select 10*10  result;
+--------+
| result |
+--------+
|    100 |
+--------+
1 row in set (0.00 sec)
```

#### 1.6.2   from子句

from:来自,from后面跟的是数据源。数据源可以有多个。返回笛卡尔积。

插入测试表

```sql
mysql> create table t1(
    -> id int,
    -> name varchar(10)
    -> );
Query OK, 0 rows affected (0.05 sec)

mysql> create table t2(
    -> field1 varchar(10),
    -> field2 varchar(10)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1 values (1,'tom'),(2,'berry');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into t2 values ('333','333'),('444','444');
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0
```

测试多个数据源

```sql
mysql> select * from t1,t2;              # 返回笛卡尔积
+------+-------+--------+--------+
| id   | name  | field1 | field2 |
+------+-------+--------+--------+
|    1 | tom   | 333    | 333    |
|    2 | berry | 333    | 333    |
|    1 | tom   | 444    | 444    |
|    2 | berry | 444    | 444    |
+------+-------+--------+--------+
4 rows in set (0.00 sec)
```

#### 1.6.3   dual表

dual表是一个伪表。在有些特定情况下,没有具体的表的参与,但是为了保证select语句的完整又必须要一个表名,这时候就使用伪表。

```sql
mysql> select 10*10 as result from dual;  #dual表是用来保证select语句的完整性。
+--------+
| result |
+--------+
|    100 |
+--------+
```

#### 1.6.4   where子句

where后面跟的是条件,在数据源中进行筛选。返回条件为真记录

MySQL支持的运算符

1. `>`	大于
2. `<`小于
3. `>=`
4. `<=`
5. `=`
6. `!=`
7. and    与
8. or      或
9. not   非

```sql
mysql> select * from stu where stusex='男';		# 查找性别是男的记录
mysql> select * from stu where stuage>=20;		# 查找年龄不低于20的记录
```

思考:如下代码输出什么

```sql
select * from stu where 1      # 返回所有数据库
select * from stu where 0		#返回空记录
```

思考:如何查找北京和上海的学生

```sql
mysql> select * from stu where stuaddress='上海' or stuaddress='北京';
+--------+---------+--------+--------+---------+------------+------+------+
| stuNo  | stuName | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+---------+--------+--------+---------+------------+------+------+
| s25301 | 张秋丽        | 男       |     18 |       1 | 北京           |   80 | NULL |
| s25302 | 李文才       | 男       |     31 |       3 | 上海          |   77 |   76 |
| s25303 | 李斯文       | 女      |     22 |       2 | 北京           |   55 |   82 |
| s25320 | Tom     | 男       |     24 |       8 | 北京           |   65 |   67 |
+--------+---------+--------+--------+---------+------------+------+------+
```

#### 1.6.5   in | not in

 上面的查询上海和北京的学生的SQL可以通过in语句来实现

```sql
mysql> select * from stu where stuaddress in ('北京','上海');
```

练习:

1、查找学号是s25301,s25302,s25303的学生

```sql
mysql> select * from stu where stuno in ('s25301','s25302','s25303');
```

2、查找年龄是18,19,20的学生

```sql
mysql> select * from stu where stuage in(18,19,20);
```

3、查找不是北京和上海的学生

```sql
mysql> select * from stu where stuaddress not in ('北京','上海');
```

#### 1.6.6   between…and|not between…and

查找某个范围的记录

1、查找年龄在18~20之间的学生

```sql
mysql> select * from stu where stuage>=18 and stuage<=20;   # 方法一

mysql> select * from stu where stuage between 18 and 20;   # 方法二
```

2、查找年龄不在18~20之间的学生

```sql
mysql> select * from stu where stuage<18 or stuage>20;		#方法一

mysql> select * from stu where not (stuage>=18 and stuage<=20);

mysql> select * from stu where stuage not between 18 and 20;
```

#### 1.6.7   is null | is not null

 脚下留心:查询一个为空的字段不能用等于,必须用is null

查找缺考的学生

```sql
mysql> select * from stu where ch is null or math is null; # 查找缺考的人
+--------+----------+--------+--------+---------+------------+------+------+
| stuNo  | stuName  | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+----------+--------+--------+---------+------------+------+------+
| s25301 | 张秋丽         | 男       |     18 |       1 | 北京           |   80 | NULL |
| s25304 | 欧阳俊雄        | 男       |     28 |       4 | 天津           | NULL |   74 |
+--------+----------+--------+--------+---------+------------+------+------+
```

查找参加考试的学生

```sql
mysql> select * from stu where ch is not null and math is not null;
```

#### 1.6.8   聚合函数

1. sum()  	   求和
2. avg()          求平均值
3. max()        求最大值
4. min()          求最小值
5. count()      求记录数

```sql
#求语文总分、语文平均分、语文最高分、语文最低分、总人数

mysql> select sum(ch) '语文总分',avg(ch) '语文平均分', max(ch) '语文最高分',min(ch) '语文最低分',count(*) '总人数' from stu;
+----------+------------+------------+------------+--------+
| 语文总分        | 语文平均分          | 语文最高分          | 语文最低分          | 总人数       |

+----------+------------+------------+------------+--------+
|      597 |    74.6250 |         88 |         55 |      9 |
+----------+------------+------------+------------+--------+
1 row in set (0.00 sec)
```

#### 1.6.9   通配符

1. _  [下划线]   表示任意一个字符
2. %  表示任意字符

练习

1、满足“T_m”的有(A、C)

A:Tom         B:Toom       C:Tam         D:Tm     E:Tmo

2、满足“T_m_”的有(B、C  )

A:Tmom   B:Tmmm  C:T1m2    D:Tmm     E:Tm

3、满足“张%”的是(A、B、C、D)

A:张三     B:张三丰     C:张牙舞爪      D:张      E:小张

4、满足“%诺基亚%”的是(A、B、C、D)

A:诺基亚2100   B:2100诺基亚   C:把我的诺基亚拿过来   D:诺基亚

#### 16.10 模糊查询(like)

```sql
# 查找姓张的同学
mysql> select * from stu where stuname like '张%';
+--------+---------+--------+--------+---------+------------+------+------+
| stuNo  | stuName | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+---------+--------+--------+---------+------------+------+------+
| s25301 | 张秋丽        | 男       |     18 |       1 | 北京           |   80 | NULL |
+--------+---------+--------+--------+---------+------------+------+------+
1 row in set (0.00 sec)
#例题
mysql> select * from stu where stuname like 'T_m';
+--------+---------+--------+--------+---------+------------+------+------+
| stuNo  | stuName | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+---------+--------+--------+---------+------------+------+------+
| s25320 | Tom     | 男       |     24 |       8 | 北京           |   65 |   67 |
+--------+---------+--------+--------+---------+------------+------+------+
1 row in set (0.00 sec)
```

#### 1.6.11 order by排序

asc:升序【默认】

desc:降序

```sql
mysql> select * from stu order by ch desc;		# 语文成绩降序排列

mysql> select * from stu order by math asc;     # 数学成绩升序排列

mysql> select * from stu order by math;       # 默认升序排列
```

多列排序

```sql
#年龄升序,成绩降序
mysql> select *,(ch+math) as '总分' from stu order by stuage asc,(ch+math) desc;
```

思考如下代码表示什么含义

```sql
select * from stu order by stuage desc,ch desc;     #年龄降序,语文降序
select * from stu order by stuage desc,ch asc;		#年龄降序,语文升序
select * from stu order by stuage,ch desc;          #年龄升序、语文降序
select * from stu order by stuage,ch; 				#年龄升序、语文升序
```

#### 1.6.12 group by 【分组查询】

将查询的结果分组,分组查询目的在于统计数据。

```sql
# 按性别分组,显示每组的平均年龄
mysql> select avg(stuage) as '年龄',stusex from stu group by stusex;
+---------+--------+
| 年龄        | stusex |
+---------+--------+
| 22.7500 | 女      |
| 25.4000 | 男       |
+---------+--------+
2 rows in set (0.00 sec)
# 按地区分组,每个地区的平均年龄
mysql> select avg(stuage) as '年龄',stuaddress from stu group by stuaddress;
+---------+------------+
| 年龄        | stuaddress |
+---------+------------+
| 31.0000 | 上海          |
| 21.3333 | 北京           |
| 27.0000 | 天津           |
| 23.0000 | 河北          |
| 23.0000 | 河南           |
+---------+------------+
5 rows in set (0.00 sec)
脚下留心:
1、如果是分组查询,查询字段必须是分组字段和聚合函数。
2、查询字段是普通字段,只取第一个值
```

 ![1536999666442](https://yp.smallkun.cn/markdown/1536999666442.png!compress!compress)

通过group_concat()函数将同一组的值连接起来显示

```sql
mysql> select group_concat(stuname),stusex from stu group by stusex;
+-------------------------------------+--------+
| group_concat(stuname)               | stusex |
+-------------------------------------+--------+
| 李斯文,诸葛丽丽,梅超风,Tabm                           | 女      |
| 张秋丽,李文才,欧阳俊雄,争青小子,Tom                          | 男       |
+-------------------------------------+--------+
2 rows in set (0.00 sec)
多学一招:【了解】
1、分组后的结果默认会按升序排列显示
2、也是可以使用desc实现分组后的降序
```

 ![1536999889281](https://yp.smallkun.cn/markdown/1536999889281.png!compress!compress)

  ![1536999987356](https://yp.smallkun.cn/markdown/1536999987356.png!compress!compress)

多列分组

```sql
mysql> select stuaddress,stusex,avg(stuage) from stu group by stuaddress,stusex;
+------------+--------+-------------+
| stuaddress | stusex | avg(stuage) |
+------------+--------+-------------+
| 上海          | 男       |     31.0000 |
| 北京           | 女      |     22.0000 |
| 北京           | 男       |     21.0000 |
| 天津           | 男       |     27.0000 |
| 河北          | 女      |     23.0000 |
| 河南           | 女      |     23.0000 |
+------------+--------+-------------+
6 rows in set (0.00 sec)
```

#### 1.6.13 having条件

```
思考:数据库中的表是一个二维表,返回的结果是一张二维表,既然能在数据库的二维表中进行查询,能否在结果集的二维表上继续进行查询?

答:可以,having条件就是在结果集上继续进行筛选。
```

例题

```sql
mysql> select * from stu where stusex='男';   # 从数据库中查找
+--------+----------+--------+--------+---------+------------+------+------+
| stuNo  | stuName  | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+----------+--------+--------+---------+------------+------+------+
| s25301 | 张秋丽         | 男       |     18 |       1 | 北京           |   80 | NULL |
| s25302 | 李文才        | 男       |     31 |       3 | 上海          |   77 |   76 |
| s25304 | 欧阳俊雄        | 男       |     28 |       4 | 天津           | NULL |   74 |
| s25318 | 争青小子        | 男       |     26 |       6 | 天津           |   86 |   92 |
| s25320 | Tom      | 男       |     24 |       8 | 北京           |   65 |   67 |
+--------+----------+--------+--------+---------+------------+------+------+
5 rows in set (0.00 sec)

mysql> select * from stu having stusex='男';   # 从结果集中查找
+--------+----------+--------+--------+---------+------------+------+------+
| stuNo  | stuName  | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+----------+--------+--------+---------+------------+------+------+
| s25301 | 张秋丽         | 男       |     18 |       1 | 北京           |   80 | NULL |
| s25302 | 李文才        | 男       |     31 |       3 | 上海          |   77 |   76 |
| s25304 | 欧阳俊雄        | 男       |     28 |       4 | 天津           | NULL |   74 |
| s25318 | 争青小子        | 男       |     26 |       6 | 天津           |   86 |   92 |
| s25320 | Tom      | 男       |     24 |       8 | 北京           |   65 |   67 |
+--------+----------+--------+--------+---------+------------+------+------+
5 rows in set (0.00 sec)
```

思考如下语句是否正确 ![1537001246956](https://yp.smallkun.cn/markdown/1537001246956.png!compress!compress)

  ![1537001432304](https://yp.smallkun.cn/markdown/1537001432304.png!compress!compress)

having和where的区别:

where是对原始数据进行筛选,having是对记录集进行筛选。 

#### 1.6.14 limit

语法:limit 起始位置,显示长度

```sql
mysql> select * from stu limit 0,2;    # 从0的位置开始,取两条数据
+--------+---------+--------+--------+---------+------------+------+------+
| stuNo  | stuName | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+---------+--------+--------+---------+------------+------+------+
| s25301 | 张秋丽        | 男       |     18 |       1 | 北京           |   80 | NULL |
| s25302 | 李文才       | 男       |     31 |       3 | 上海          |   77 |   76 |
+--------+---------+--------+--------+---------+------------+------+------+
2 rows in set (0.00 sec)
 
mysql> select * from stu limit 2,2;    # 从2的位置开始,取两条数据
+--------+----------+--------+--------+---------+------------+------+------+
| stuNo  | stuName  | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+----------+--------+--------+---------+------------+------+------+
| s25303 | 李斯文        | 女      |     22 |       2 | 北京           |   55 |   82 |
| s25304 | 欧阳俊雄        | 男       |     28 |       4 | 天津           | NULL |   74 |
+--------+----------+--------+--------+---------+------------+------+------+
```

起始位置可以省略,默认是从0开始

```sql
mysql> select * from stu limit 2;
+--------+---------+--------+--------+---------+------------+------+------+
| stuNo  | stuName | stuSex | stuAge | stuSeat | stuAddress | ch   | math |
+--------+---------+--------+--------+---------+------------+------+------+
| s25301 | 张秋丽        | 男       |     18 |       1 | 北京           |   80 | NULL |
| s25302 | 李文才       | 男       |     31 |       3 | 上海          |   77 |   76 |
+--------+---------+--------+--------+---------+------------+------+------+
2 rows in set (0.00 sec)
```

例题:找出班级总分前三名

```sql
mysql> select *,(ch+math) total from stu order by total desc limit 0,3;
+--------+----------+--------+--------+---------+------------+------+------+-------+
| stuNo  | stuName  | stuSex | stuAge | stuSeat | stuAddress | ch   | math | total |
+--------+----------+--------+--------+---------+------------+------+------+-------+
| s25318 | 争青小子        | 男       |     26 |       6 | 天津           |   86 |   92 |   178 |
| s25321 | Tabm     | 女      |     23 |       9 | 河北          |   88 |   77 |   165 |
| s25302 | 李文才        | 男       |     31 |       3 | 上海          |   77 |   76 |   153 |
+--------+----------+--------+--------+---------+------------+------+------+-------+
```

多学一招:limit在update和delete语句中也是可以使用的。

#### 1.6.15 查询语句中的选项

查询语句中的选项有两个:

1、     all:显示所有数据 【默认】

2、     distinct:去除结果集中重复的数据

```sql
mysql> select distinct stuaddress from stu;
+------------+
| stuaddress |
+------------+
| 上海          |
| 天津           |
| 河南           |
| 河北          |
| 北京           |
+------------+
5 rows in set (0.00 sec)
```

## 1.7 union(联合)

插入测试数据

```sql
mysql> create table GO1(
    -> id int primary key,
    -> name varchar(20));
Query OK, 0 rows affected (0.06 sec)

mysql> insert into Go1 values (1,'李白'),(2,'张秋丽');
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0
```

#### 1.7.1 union的使用

作用:将多个select语句结果集纵向联合起来

```sql
语法:select 语句 union [选项] select 语句 union [选项] select 语句
mysql> select stuno,stuname from stu union select id,name from Go1;
+--------+----------+
| stuno  | stuname  |
+--------+----------+
| s25301 | 张秋丽         |
| s25302 | 李文才        |
| s25303 | 李斯文        |
| s25304 | 欧阳俊雄        |
| s25305 | 诸葛丽丽         |
| s25318 | 争青小子        |
| s25319 | 梅超风        |
| s25320 | Tom      |
| s25321 | Tabm     |
| 1      | 李白         |
| 2      | 张秋丽         |
+--------+----------+
```

例题:查询上海的男生和北京的女生

```sql
mysql> select stuname,stuaddress,stusex from stu where (stuaddress='上海' and stusex='男') or (stuaddress='北京' and stusex='女');
+---------+------------+--------+
| stuname | stuaddress | stusex |
+---------+------------+--------+
| 张秋丽        | 上海          | 男       |
| 梅超风       | 北京           | 女      |
+---------+------------+--------+
2 rows in set (0.00 sec)

mysql> select stuname,stuaddress,stusex from stu where stuaddress='上海' and stusex='男' union select stuname,stuaddress,stusex from stu where stuaddress='北京' and stusex='女';
+---------+------------+--------+
| stuname | stuaddress | stusex |
+---------+------------+--------+
| 张秋丽        | 上海          | 男       |
| 梅超风       | 北京           | 女      |
+---------+------------+--------+
2 rows in set (0.02 sec)
```

#### 1.7.2   union的选项

union的选项有两个

1、     all:显示所有数据

2、     distinct:去除重复的数据【默认】

```sql
mysql> select name from go1 union select stuname from stu;
+----------+
| name     |
+----------+
| 李白         |
| 张秋丽         |
| 李文才        |
| 李斯文        |
| 欧阳俊雄        |
| 诸葛丽丽         |
| 争青小子        |
| 梅超风        |
| Tom      |
| Tabm     |
+----------+
```

默认是去重复的

```sql
mysql> select name from go1 union all select stuname from stu;  # all不去重复记录
+----------+
| name     |
+----------+
| 李白         |
| 张秋丽         |
| 张秋丽         |
| 李文才        |
| 李斯文        |
| 欧阳俊雄        |
| 诸葛丽丽         |
| 争青小子        |
| 梅超风        |
| Tom      |
| Tabm     |
+----------+
```

#### 1.7.3   union的注意事项

1、     union两边的select语句的字段个数必须一致 

2、     union两边的select语句的字段名可以不一致,最终按第一个select语句的字段名。

 3、     union两边的select语句中的数据类型可以不一致。