# 行(row):被称为数据/记录
# 列(column):被称为字段
# 每一个字段都有:字段名、数据类型、约束等属性
姓名 年龄(列:字段)
-----------------------
张三 20 (行:数据/记录)
类别 | 具体 |
---|---|
DQL | 数据查询语言(凡是带有select关键字的都是查询语言) |
DML | 数据操作语言(凡是对表中数据进行增删改的都是DML) |
DDL | 数据定义语言(主要操纵的是表的结构。不是表中的数据) |
TCL | 事务控制语言(事物提交、事物回滚…) |
DCL | 数据控制语言(授权、撤销权限…) |
命令 | 作用 | 具体说明 |
---|---|---|
\c | 终止命令的输入 | |
exit | 退出mysql | |
select version(); | 查看mysql数据库版本号 | |
select database(); | 查看当前使用的数据库 | |
show databases; | 查看所有数据库 | |
use 数据库名称 | 使用数据库 | |
create database 数据库名称; | 创建数据库 | |
drop database 数据库名称; | 删除数据库 | |
show tables; | 查看数据库全部表 | |
select * from car; | 查看表中数据 | 从car表中查询所有数据,*代表全部 |
desc 表名; | 查看表的结构 | |
show create table 表名; | 显示创建表时的语句 | |
select @@tx_isolation; | 查看隔离级别 | |
以上命令不区分大小写 |
select 'abc' from emp;
+-----+
| abc |
+-----+
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
+-----+
符号 | 作用 | 实例 |
---|---|---|
= | 等于 | |
<>或!= | 不等于 | |
< | 小于 | |
<= | 小于等于 | |
> | 大于 | |
>= | 大于等于 | |
between…and… | 两值之间(>=and<=) | |
is null | 为空(is not null 不为空) | |
and | 并且 | |
or | 或者 | |
in | 包含,相当于多个or(not in不包含) | select * from car where car_ID in (‘CA001’,‘CA006’); |
not | 非 | |
like | 为模糊查询,支持%或下划线匹配(%匹配任意个字符,_一个下划线只匹配一个字符) | |
and优先级比or高 |
# 模糊查询
# 查询中间字符
select * from car where car_ID like '%00%'
# 查询某开头
select * from car where car_ID like 'CA%'
# 查询某结尾
select * from car where car_ID like '%001'
# 当员工的岗位为MANAGER的时候工资上调10%,当为SALESMAN的时候上调50%,其他正常
select
ename,
job,
sal oldsal,
(case job when 'MANAGER' then sal *1.1 when 'SALESMAN' then sal*1.5 else sal end) newsal
from emp;
+--------+-----------+---------+---------+
| ename | job | oldsal | newsal |
+--------+-----------+---------+---------+
| SMITH | CLERK | 800.00 | 800.00 |
| ALLEN | SALESMAN | 1600.00 | 2400.00 |
| WARD | SALESMAN | 1250.00 | 1875.00 |
| JONES | MANAGER | 2975.00 | 3272.50 |
| MARTIN | SALESMAN | 1250.00 | 1875.00 |
| BLAKE | MANAGER | 2850.00 | 3135.00 |
| CLARK | MANAGER | 2450.00 | 2695.00 |
| SCOTT | ANALYST | 3000.00 | 3000.00 |
| KING | PRESIDENT | 5000.00 | 5000.00 |
| TURNER | SALESMAN | 1500.00 | 2250.00 |
| ADAMS | CLERK | 1100.00 | 1100.00 |
| JAMES | CLERK | 950.00 | 950.00 |
| FORD | ANALYST | 3000.00 | 3000.00 |
| MILLER | CLERK | 1300.00 | 1300.00 |
+--------+-----------+---------+---------+
函数 | 作用 |
---|---|
Lower | 转换小写 |
upper | 转换大写 |
substr | 取子串(substr(被截取的字符串,起始下标(从1开始),截取的长度),不写长度默认截到最后一个字符 |
length | 取长度 |
trim | 去空格 |
str_to_date | 将字符串转换成日期 |
date——format | 格式化日期 |
format | 设置千分位 |
round | 四舍五入 |
rand() | 生成0-1随机数 |
ifnull | 将null转换为一个具体值 |
concat | 拼接字符串(concat(字符串1,字符串2)) |
now | 获取当前系统时间,为datetime类型 |
# 四舍五入函数,第二个参数为保留几位小数
select round(123.54,3);
+-----------------+
| round(123.54,3) |
+-----------------+
| 123.540 |
+-----------------+
select round(123.54,-2);
+------------------+
| round(123.54,-2) |
+------------------+
| 100 |
+------------------+
# null转换函数
# 把null当成为0
select ename,ifnull(comm,0) from emp;
+--------+----------------+
| ename | ifnull(comm,0) |
+--------+----------------+
| SMITH | 0.00 |
| ALLEN | 300.00 |
| WARD | 500.00 |
| JONES | 0.00 |
| MARTIN | 1400.00 |
| BLAKE | 0.00 |
| CLARK | 0.00 |
| SCOTT | 0.00 |
| KING | 0.00 |
| TURNER | 0.00 |
| ADAMS | 0.00 |
| JAMES | 0.00 |
| FORD | 0.00 |
| MILLER | 0.00 |
+--------+----------------+
# 数字格式化:fromat(数字,'格式')
select format(sal,'$999,999') from emp;
+------------------------+
| format(sal,'$999,999') |
+------------------------+
| 800 |
| 1,600 |
| 1,250 |
| 2,975 |
| 1,250 |
| 2,850 |
| 2,450 |
| 3,000 |
| 5,000 |
| 1,500 |
| 1,100 |
| 950 |
| 3,000 |
| 1,300 |
+------------------------+
# str_to_date:将字符串varchar类型转换成date类型
# 如果刚好是年月日格式就可以省略不写
insert into t_user values(1,'san',str_to_date('10-11-1997','%d-%m-%Y'));
# %Y 年
# %m 月
# %d 日
# %h 时
# %i 分
# %s 秒
# date_format:将date类型转换成具有一定格式的varchar字符串类型
select no,name,date_format(birth,'%m/%d/%Y') from t_user;
+------+------+-------------------------------+
| no | name | date_format(birth,'%m/%d/%Y') |
+------+------+-------------------------------+
| 1 | san | 10/11/1997 |
| 1 | san | 11/10/1997 |
+------+------+-------------------------------+
select * from emp where sal>min(sal);
ERROR 1111 (HY000): Invalid use of group function
函数 | 作用 |
---|---|
count | 计数 |
sum | 求和 |
avg | 平均值 |
max | 最大值 |
min | 最小值 |
# 计数
select count(ename) from emp;
+--------------+
| count(ename) |
+--------------+
| 14 |
+--------------+
# 按岗位分组算各个岗位的平均工资
select job,avg(sal) from emp group by job;
+-----------+-------------+
| job | avg(sal) |
+-----------+-------------+
| ANALYST | 3000.000000 |
| CLERK | 1037.500000 |
| MANAGER | 2758.333333 |
| PRESIDENT | 5000.000000 |
| SALESMAN | 1400.000000 |
+-----------+-------------+
# 在同一部门中找不同岗位的最高工资
select deptno,job,max(sal) from emp group by deptno,job;
+--------+-----------+----------+
| deptno | job | max(sal) |
+--------+-----------+----------+
| 10 | CLERK | 1300.00 |
| 10 | MANAGER | 2450.00 |
| 10 | PRESIDENT | 5000.00 |
| 20 | ANALYST | 3000.00 |
| 20 | CLERK | 1100.00 |
| 20 | MANAGER | 2975.00 |
| 30 | CLERK | 950.00 |
| 30 | MANAGER | 2850.00 |
| 30 | SALESMAN | 1600.00 |
+--------+-----------+----------+
select deptno,max(sal) from emp group by deptno having max(sal)>3000;
+--------+----------+
| deptno | max(sal) |
+--------+----------+
| 10 | 5000.00 |
+--------+----------+
select distinct job from emp;
+-----------+
| job |
+-----------+
| CLERK |
| SALESMAN |
| MANAGER |
| ANALYST |
| PRESIDENT |
+-----------+
select distinct deptno,job from emp;
+--------+-----------+
| deptno | job |
+--------+-----------+
| 20 | CLERK |
| 30 | SALESMAN |
| 20 | MANAGER |
| 30 | MANAGER |
| 10 | MANAGER |
| 20 | ANALYST |
| 10 | PRESIDENT |
| 30 | CLERK |
| 10 | CLERK |
+--------+-----------+
select count(distinct job) from emp;
+---------------------+
| count(distinct job) |
+---------------------+
| 5 |
+---------------------+
# 不做条件限制
select ename,dname from emp,dept;
56 rows in set (0.01 sec)
# 条件限制
# 当两个表的字段名相等时,可以加上表名.的形式进行区分
# 加条件只会减少查询结果,不会减少匹配次数
select ename,dname from emp e,dept d where e.deptno=d.deptno;
# 92语法
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)
# 92语法
# 缺点:结构不够清晰,表的连接条件和后期进一步筛选条件都烦在where后面
select
ename,dname
from
emp e,dept d
where
e.deptno=d.deptno;
# 99语法
# 优点:表连接的条件与后续筛选的条件分离
select
ename,dname
from
emp e
inner join # inner可以省略,带inner可读性更高
dept d
on
e.deptno=d.deptno;
select
e.ename,e.sal,s.grade
from
emp e
inner join
salgrade s
on
e.sal between s.losal and s.hisal;
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
14 rows in set (0.00 sec)
select
a.ename 员工名,a.ename 领导名
from
emp a
join
emp b
on
a.mgr=b.empno;
+--------+--------+
| 员工名 | 领导名 |
+--------+--------+
| SMITH | SMITH |
| ALLEN | ALLEN |
| WARD | WARD |
| JONES | JONES |
| MARTIN | MARTIN |
| BLAKE | BLAKE |
| CLARK | CLARK |
| SCOTT | SCOTT |
| TURNER | TURNER |
| ADAMS | ADAMS |
| JAMES | JAMES |
| FORD | FORD |
| MILLER | MILLER |
+--------+--------+
13 rows in set (0.01 sec)
select
e.ename,d.dname
from
emp e
right outer join # outer可以省略
dept d
on
e.deptno=d.deptno;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
| NULL | OPERATIONS |
+--------+------------+
15 rows in set (0.00 sec)
select
...
from
a
join
b
on
a和b的连接条件
join
c
on
a和c的连接条件
......
select
e.ename,e.sal,d.dname,s.grade
from
emp e
join
dept d
on
e.deptno =d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal;
+--------+---------+------------+-------+
| ename | sal | dname | grade |
+--------+---------+------------+-------+
| SMITH | 800.00 | RESEARCH | 1 |
| ALLEN | 1600.00 | SALES | 3 |
| WARD | 1250.00 | SALES | 2 |
| JONES | 2975.00 | RESEARCH | 4 |
| MARTIN | 1250.00 | SALES | 2 |
| BLAKE | 2850.00 | SALES | 4 |
| CLARK | 2450.00 | ACCOUNTING | 4 |
| SCOTT | 3000.00 | RESEARCH | 4 |
| KING | 5000.00 | ACCOUNTING | 5 |
| TURNER | 1500.00 | SALES | 3 |
| ADAMS | 1100.00 | RESEARCH | 1 |
| JAMES | 950.00 | SALES | 1 |
| FORD | 3000.00 | RESEARCH | 4 |
| MILLER | 1300.00 | ACCOUNTING | 2 |
+--------+---------+------------+-------+
14 rows in set (0.00 sec)
select
..(select)
from
..(select)
where
..(select)
# where中的子查询
select
ename,sal
from
emp
where
sal>(select min(sal) from emp);
+--------+---------+
| ename | sal |
+--------+---------+
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
13 rows in set (0.00 sec)
# from中的子查询
# from中的子查询,可以将查询结果看做一张临时表
select t.*,s.grade
from
(select job,avg(sal) as avgsal from emp group by job) t
join
salgrade s
on
t.avgsal between s.losal and s.hisal;
+-----------+-------------+-------+
| job | avgsal | grade |
+-----------+-------------+-------+
| ANALYST | 3000.000000 | 4 |
| CLERK | 1037.500000 | 1 |
| MANAGER | 2758.333333 | 4 |
| PRESIDENT | 5000.000000 | 5 |
| SALESMAN | 1400.000000 | 2 |
+-----------+-------------+-------+
5 rows in set (0.01 sec)
select ename,job from emp where job ='MANAGER'
union
select ename,job from emp where job ='SALESMAN';
+--------+----------+
| ename | job |
+--------+----------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| MARTIN | SALESMAN |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)
# 取出工资前五的人
select
ename,sal
from
emp
order by
sal desc
limit 5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| FORD | 3000.00 |
| SCOTT | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
5 rows in set (0.00 sec)
select 5
...
from 1
...
where 2
...
group by 3
...
having 4
...
order by 6
...
limit ... 7
# 以上顺序不可颠倒
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型...
);
# 表名建议以t_或者tbl_开始,可读性强,见名知意
# 字段名见名知意
create table t_student(
no int,
name varchar(32),
age int(3),
email varchar(255)
);
drop table 表名;
# 表不存在时会报错
drop table if exists 表名;
# 如果表存在就删除
insert into 表名(字段名1,字段名2···) values(值1,值2····);
# 字段与值要一一对应
# 字段可以省略,省略后默认都写上了
# 插入多条记录
insert into t_student values
(1,'1',3,'1'),
(1,'1',3,'1');
# 将一个查询结果插入表
# 查询结果需要符合被插入的表结构
insert into dept select * from emp;
create table 表名(
字段名1 数据类型 default 默认值,
字段名2 数据类型,
字段名3 数据类型...
);
# 格式:update 表名 set 字段名1=值1,字段名2=值2....where 条件;
# 没有条件限制会导致所有数据全部更新
# 语法格式:delete from 表名 where 条件;
# 没有条件限制会导致所有数据全部删除
# 表中数据被删除,内存不会被释放,效率比较低,但是数据可以被回复
# truncate语句删除
# 效率较高但是不支持回滚
truncate table dept;
# 将一个查询结果当做一张表新建
# 可以完成表的快速复制
# 表中的数据也会存在
create table emp2 as select * from emp;
数据类型 | 含义 | 限制 |
---|---|---|
varchar | 可变长度的字符串,会根据实际的数据长度动态分配空间 | 最长255 |
char | 定长字符串,不管实际的数据长度,分配固定的空间 | 最长255 |
int | 数字整数型 | 最长11 |
bigint | 数字长整型 | |
float | 单精度浮点型 | |
double | 双精度浮点型 | |
date | 短日期,包括年月日 | |
datetime | 长日期,包括年月日时分秒 | |
clob | 字符大对象,最多可以存储4G的字符串 | |
blob | 二进制大对象,专门用来存储图片,声音,视频等流媒体数据 | 插入数据必须使用IO流 |
# 非空约束的字段不能为NULL
# 只有列级约束
create table emp3(
no int not null
);
# 唯一性约束的字段不能重复
create table t_vip(
id int,
name varchar(255) unique
);
# 多字段联合起来唯一
create table t_vip(
id int,
name varchar(255),
unique(id,name)
);
# 主键约束:一种约束
# 主键字段:字段加了主键约束
# 主键值:主键字段里的每一个值都为主键值
# 主键值是每一行记录的唯一标识
# 任何一张表都应该有主键,否则是无效的
# 主键不能重复不能为空
# 分为单一主键与复合主键(多个字段联合),不建议使用复合主键
# 主键只能有一个
# 主键建议使用int,bigint,char等定长类型
# 还可以分为自然主键和业务主键
# 自然主键(使用较多):主键值是一个自然数,和业务没关系
# 业务主键:和业务紧密关联
# 在mysql中可以使用auto_increment自增来维护主键,默认从1开始以1递增
create table t_vip(
id int primary key auto_increment,
name varchar(255)
);
# 外键约束:一种约束
# 外键字段:字段加了外键约束
# 外键值:外键字段里的每一个值都为外键值
# 如果吧全部数据都烦在一张表里,数据冗余,空间浪费,可以设计两张表来节省空间,这时候就需要添加外键约束,确保两表链接数据正确
# 被外键引用的表为父表,删除表的时候要先删子表,创建表的时候先创父表,删除数据时先删子表,插入数据时先插父表
# 被外键引用的字段必须有unique约束,外键值可以为null
CREATE table t_class(
classno int primary key,
classname varchar(255)
);
CREATE TABLE t_student(
no int primary key auto_increment,
name varchar(255),
cno int ,
foreign key(cno) references t_class(classno)
);
CREATE TABLE `emp` (
`EMPNO` int(4) NOT NULL,
`ENAME` varchar(10) DEFAULT NULL,
`JOB` varchar(9) DEFAULT NULL,
`MGR` int(4) DEFAULT NULL,
`HIREDATE` date DEFAULT NULL,
`SAL` double(7,2) DEFAULT NULL,
`COMM` double(7,2) DEFAULT NULL,
`DEPTNO` int(2) DEFAULT NULL,
PRIMARY KEY (`EMPNO`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 auto_increment=100
# 指定存储引擎和字符集,指定自增从100开始
事务命令:
一个事务起始就是一个完整的业务逻辑
什么是一个完整的业务逻辑?
假设转账,从A账户向B账户转账10000
将A账户的钱减去10000(update语句)
将B账户的钱加上10000(update语句)
这就是一个完整的业务逻辑
# 只有DML语句才有事物这一说,其他语句和事物无关
insert、delete、update才有关,其他没有关系
# 正是因为做某件事需要多条DML语句共同联合起来才能完成,所以才需要事务的存在
# 事务本质就是多条DML语句同时成功或同时失败
事务是怎么做到多条DML语句同时成功或同时失败的?
提交事务
回滚事务
mysql支持自动提交事务,每执行一次DML语句,则提交一次
如何关闭mysql的自动提交?
# 执行:
start transaction
事务的四个特性:
事务隔离性
A教室和B教室中间有一道墙,这道墙越厚,表示隔离的级别就越高
# 事务隔离级别从低到高为:
读未提交:read uncommitted
事务A可以读取到事务B未提交的数据。
这种隔离级别的存在的问题就是:
脏读现象(Dirty Read)
称为读到了脏数据
这种级别一般都是理论上的,一般都是从第二级起步
读已提交:read committed
事务A只能读取到事务B提交后的数据
这种隔离级别解决了脏读现象,但是不可重复读取数据
这种隔离级别是比较真实的数据,每一次读到的数据是绝对真实
可重复读:repeatable read
事务A开启后,不管多久,每一次在事务A中读取到的数据都是一致的,即使是事务B将数据已经修改,并且提交了。
解决了不可重复读取数据,但是会出现幻影读。每一次读到的数据都是幻象,不够真实
mysql默认的隔离级别
序列化/串行化:serializable
效率最低,解决了所有的问题。
别是事务排队,不能并发
每一次读取到的数据时最真实的,并且效率是最低的
索引是在数据库表的字段上添加,是为了提高查询效率存在的一种机制。一张表的一个字段可以添加一个索引,多个字段联合起来也可以添加。相当于一本书的目录
索引是各种数据库进行优化的重要手段。优化的时候优先考虑的因素就是索引
mysql查询主要就是两种方式:
索引的实现原理
mysql会自动在主键上添加索引对象,如果以一个字段上有unique约束的话,也会自动创建索引对象
什么时候会添加索引?
数据量庞大
该字段经常出现在where后面,一条件的形式存在,也就是说这个字段总是被扫描
该子段很少的DML操作(因为DML后,索引需要重新排序)
建议不要随意添加索引,因为索引是需要维护的,太多会降低系统性能,建议通过主键查询,建议通过unique约束的字段进行查询,效率是比较高的
索引的创建与删除
创建索引
create index 序列名 on 表名(字段)
删除索引
drop index 索引名 index on 表名;
在mysql中怎么查看一个sql语句是否使用了索引进行检索
# 对sql语句进行解释,可以查看检索的行数,type=all则是全表扫描
explain select * from emp where ename='king';
索引的失效
# 在模糊查询时尽量避免以'%'开头
select * from emp where ename like '%T';
# 使用or的时候要求两边的条件字段都要有索引才会走索引
# 使用复合索引的时候,没有使用左侧的列查找,索引失效
create index emp_job_sal_index on emp(job,sal);# 复合索引
explain select * from emp where job='MANAGER';# 使用索引
explain select * from emp where sal=800;# 索引失效
# 在where当中索引字段参加了运算
explain select * from emp where sal+1=800;# 索引失效
# 在where当中索引字段使用了函数
explain select * from emp where lower(ename)='smith';
索引的分类
单一索引:一个字段上添加索引
复合索引:多个字段添加索引
主键索引:主键上添加索引
唯一性索引:在有unique约束字段上添加索引
唯一性比较弱的字段上添加索引用处不大
什么是视图?
创建视图对象和删除视图对象
创建视图
# 用一个查询结果创建视图
create view 视图名 as select * from emp;
# 只有DQL语句才能以view的形式创建
删除视图对象
drop view 视图名;
视图可以做什么?
视图的作用
视图是用来简化sql对象
create view
emp_dept_view
as
select
e.ename,e.sal,d.dname
from
emp e
join
dept d
on
e.deptno=d.deptno;
# 默认把DQL语句简化为emp_dept_view视图
新建用户
# username--你要创建的用户名
# password--该用户密码
create user username identified by 'password'
数据导出:
# 只能在windows dos命令窗口
# 导出整个数据库
mysqldump 数据库名>路径名 -urrot -p123456
# 导出数据库中的某个表
mysqldump 数据库名>路径名 表名 -urrot -p123456
数据导入
source 路径
什么是数据库设计范式?
第一范式
第二范式
第三范式
第一范式
最核心,最重要的范式,所有表的设计都需要满足
必须有主键,并且每一个字段都是原子性不可再分
学生编号 联系方式
1001 1213546548
1002 1354654654
# 以上不符合第一范式:没有主键,并且联系范式字段可以分为邮箱与联系电话
第二范式
学生编号+ 教师编号(pk) 学生姓名 老师姓名
1001 001 张三 汪老师
# 不符合第二范式,学生姓名字段依赖学生编号,老师姓名字段依赖教师编号,产生部分依赖
# 多对多,三张表,关系表两个外键
第三范式
学生编号(pk) 学生姓名 班级编号 班级名称
1001 张三 01 一年一班
# 满足第一范式
# 满足第二范式,主键不是复合主键,没有产生部分依赖
# 不满足第三范式,一年一班依赖01,01依赖1001,产生传递依赖
# 一对多,两张表,多的表加外键
数据库设计三范式是理论上的,实践和理论有偏差,最终的目的都是为了满足客户需求,有时候会拿冗余换执行速度,因为在sql中,表和表之间连接的次数越多,效率越低