class-notes/课件/MySQL/3. 数据库设计与查询语句.md
2025-02-06 22:43:19 +08:00

991 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 测试数据
```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 一对多 1N
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 多对多NM
主表中的一条记录对应从表中的多条记录,从表中的一条记录对应主表中的多条记录
班级和讲师的关系
![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-REntityRelationship实体关系图
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
ATom BToom CTam DTm ETmo
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 B2100诺基亚 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语句中的数据类型可以不一致。