MySQL

数据库DataBase

执行顺序是 on > where > having
on 是对 join的两张表进行过滤
where 是对单个表进行约束 再生成一个表
having 对单个表进行过滤而不是生成表 可以跟聚合函数 因为是对已存在表的过滤
MySQL属于关系型数据库
表与表之间是互相关联的
MySQL由RDBMS和生成的数据库文件组成
innoDB MyISAM 都是表引擎
innoDB 属于索引组织表 事务安全(要么不做要么做完整) 外键 行级锁
MyISAM 属于堆表 不支持事务 不支持外键 表级锁
写多读少的应用中InnoDB插入性能更稳定 且高并发因为行级锁 InnoDB更有优势
读多写少的应用中MyISAM读取性能更稳定 但高并发因为表级锁可能不如InnoDB

数据库的优点
  • 持久化存储
  • 读写速度快
  • 保证数据的有效性
  • 对程序的支持性好 容易扩展

数据库的本质是一个文件系统
根据特殊的算法数据库的性能要比普通文件更有优势
在linux下mysql数据库文件储存在/var/lib/mysql
必须切换到管理员身份才能访问/var/lib/mysql

数据库中以为组织单位储存数据
表中的列称为字段
表中的行称为记录
能唯一标记记录字段称为主键

DBMS

数据库管理系统
DBMS 是一个程序用来管理数据库
数据库又分为 关系型数据库 非关系型数据库
数据库仅仅是数据库文件需要通过DBMS增删改查管理
而MySQL 属于C/S模型 所以分为 RDBMS客户端RDBMS服务器
客户端与服务器之间通过SQL语言进行控制

关系型数据库:
  • Oracle 大型项目中使用
  • MySQL WEB中广泛使用的关系型数据库
  • MS SQL Server 微软的项目中使用
  • SQLite 轻量级数据库 用于移动平台

SQL

结构化查询语言
用于RDBMS_clientRDBMS_server之间的沟通
SQL是用来操作RDBMS的语言 当前的关系型数据库都支持SQL
所以SQL可以操作 oracle mysql ms sql server sqlite

SQL语句主要分为:
  • DQL 数据查询语言 用于对数据进行查询
  • SML 数据操作语言 用于对数据进行增删改
  • TPL 事务处理语言 用于对事务进行处理
  • DCL 数据控制语言 用于进行授权与权限回收
  • DDL 数据定义语言 用于进行数据库和表的管理等
  • CCL 指针控制语言 通过控制指针完成表的操作

SQL是一门语言 专门用来操作关系型数据库
SQL语句不区分大小写
SQL语句结束时要输入;结尾

服务器端和客户端的安装

安装 sudo apt-get install mysql-server
启动 sudo service mysql start
停止 sudo service mysql stop
重启 sudo service mysql restart

安装 sudo apt-get install mysql-client

mysql的配置文件

/etc/mysql/mysql.cnf加载的配置文件目录

  • /etc/mysql/conf.d/
  • /etc/mysql/mysql.conf.d/

bind-address 表示服务器绑定的IP 默认为127.0.0.1
port 表示端口 默认为3306
datadir 表示数据库目录 默认为/var/lib/mysql
general_log_file 表示普通日志 默认为/var/log/mysql/mysql.log/mysql/mysql
log_error 表示错误日志 默认为/var/log/mysql/error.log/mysql/error

数据类型

创建数据库时指定编码排序编码
数据表默认使用数据库的编码格式
使用数据类型的原则: 够用就行 尽量使用取值范围小的 而不用大的 节省储存空间

常用数据类型
  • 整数: int bit
  • 小数: decimal
  • 字符串: varchar(N) char(N)
  • 日期时间: date time datetime
  • 枚举类型: enum
  • 集合类型: set
特别说明的类型

int 表示整数 如int(2)表示的是显示宽度 不是限制个数 也不是最大数
decimal 表示浮点数 如decimal(5,2)表示共存5位数 小数占2位 整数占3位
char(N) 表示固定长度的字符串必须指定长度 如char(3)三个字符个数 填充"ab"会补充空格为"ab "
varchar(N) 表示可变长度的字符串必须指定长度 如varchar(3)最大字符个数 填充"ab"是就会存储"ab"
text表示存储大文本 当字符大于4000时推荐使用
图片 音频 视频 不储存在数据库而是上传到某个服务器 在表中存储路径

数值类型
类型 字节大小 有符号范围(Signed) 无符号范围(Unsigned)
TINYINT 1 -128 ~ 127 0 ~ 255
SMALLINT 2 -32768 ~ 32767 0 ~ 65535
MEDIUMINT 3 -8388608 ~ 8388607 0 ~ 16777215
INT/INTEGER 4 -2147483648 ~ 2147483647 0 ~ 4294967295
BIGINT 8 -9223372036854775808 ~ 9223372036854775807 0 ~ 18446744073709551615

默认数值类型是有符号的 定义无符号数值在类型后加上unsigned 并且 unsigned 必须写在类型后
int unsigned tinyint unsigned

字符串
类型 字节大小 示例
CHAR(N) 0-255 类型:char(3) 输入 'ab', 实际存储为'ab ', 输入'abcd' 实际存储为 'abc'
VARCHAR(N) 0-255 类型:varchar(3) 输 'ab',实际存储为'ab', 输入'abcd',实际存储为'abc'
BLOB 0-65536 二进制且区分大小写
TEXT 0-65535 大文本
日期时间类型
类型 字节大小 示例
DATE 4 '2020-01-01'
TIME 3 '12:29:59'
DATETIME 8 '2020-01-01 12:29:59'
YEAR 1 '2017'
TIMESTAMP 4 '1970-01-01 00:00:01' UTC ~ '2038-01-01 00:00:01' UTC

如果需要系统自动填入日期或时间或者年份 在设置时间类型时默认值设置为 current_timestamp() 函数

约束

通过约束保证数据的稳定可靠

  • 主键 primary key 物理上存储的顺序
  • 非空 not null 此字段不允许填写空值
  • 增长 auto_increment 此字段的值自动增长
  • 唯一 unique 此字段的值不允许重复
  • 默认 default 指定此字段每个记录的默认值
  • 外键 foreign key 约束为关系字段 表中字段中的值必须在其他表中字段的值的范围内 这样的字段类型称为外键

当为关系字段填写值时 先到关联的表中查询此值是否存在 如果存在则填写成功 如果不存在则填写失败并抛出异常 所以外键影响性能 可以在代码阶段通过逻辑避免需要使用外键约束的必要

MySQL的基本用法

连接和退出

链接数据库 mysql -u root -p mysql -u 用户名 -p 密码
退出数据库 exit quit Ctrl+D
use 数据库名; 使用指定数据库

显示

show databases; 显示所有数据库
show create database 数据库名; 显示创建数据库的信息
show tables; 显示所有数据表
show create table 表名; 显示创建数据表的信息
show character set 查看可用的字符集
show collation 查看可用的排序规则

select now(); 查看当前时间
select version(); 查看数据库版本
select database(); 查看当前使用的数据库
desc 表名; 查看数据表的结构 显示为字段 类型 约束

创建删除数据库

create database 数据库名 charset=编码 collate=排序编码; 创建数据库指定编码及排序规则 表默认使用数据库的编码格式 不指定编码默认使用latin1
drop database 数据库名; 删除数据库

create database pythondb charset=utf8 collate=utf8_general_ci;
drop database pythondb;
修改数据库属性

alter database 数据库名 charset=编码; 修改数据库的编码格式
alter database 数据库名 collate=排序编码; 修改数据库排序规则

alter database pythondb charset=latin1;
alter database pythondb collate=utf8_general_ci;
创建删除数据表

create table 表名称(字段 类型 约束[,字段 类型 约束]); 创建数据表并设置多个字段
drop table 表名; 删除数据表

create table students(id int primary key, name varchar(10));
drop table students;
修改数据表属性

alter table 表名 add 字段 类型 约束; 添加表中的字段
alter table 表名 change 原字段 新字段 类型 约束; 修改已经存在的字段
alter table 表名 modify 字段 类型 约束; 修改已存在字段的类型和约束
alter table 表名 drop 字段; 删除数据表中的字段

alter table students add name varchar(4) not null;
alter table students change age birthday datetime;
alter table students modify birthday date not null;
alter table students drop birthday;
查询

使用select查询时 填入的查询字段的顺序 决定了显示的顺序 where 类似于判断 用于判断范围
select * from 表名; 查看数据表中的所有数据
select 字段[,字段] from 表名 where 条件; 查看满足条件的某些字段的信息
select 字段 as 别名[,字段 as 别名] from 表名 where 条件; as 设置别名方便查看

select * from students;
select name, id from students where id =9;
select id as 序号, name as 姓名 from students where id>3;
插入

insert into 表名 values(记录1, 记录2, 记录3); 向表中插入记录
插入的字段属于自动增长时可以填充 0 null default
插入的字段属于枚举时可以填充枚举的 序号
使用全列插入时即使有默认值的字段也应该填写

insert into students values(0, "老王", "男");  
insert into students values(null, "老王", 1);
部分插入

部分插入时NOT NULL 的部分必须填充 没有填充的部分根据默认值填充 没有默认值的部分为NULL
insert into 表名 (字段1, 字段2) values(记录1, 记录2); 向表中插入部分记录

insert into students (id, name) values(default, "老李");
多行插入

insert into 表名 values(记录1, 记录2), (记录1, 记录2); 一次插入多行
insert into 表名 (字段1, 字段2) values(记录1, 记录2), (记录1, 记录2); 多行部分插入

insert into students values(null, "小王"), (0, "小李");
insert into students (id , name) values(default, "小王"), (null, "小李");
修改

where 类似于判断 用于判断范围 set 字段 指定列 where 条件 指定行
update 表名 set 字段=值; 修改数据表中所有字段的值
update 表名 set 字段1=值1, 字段2=值2 where 条件; set指定列和值 where指定行范围

update students set age=18;
update students set name="小李", age=18 where id=4;
删除

物理删除表内容
delete from 表名; 清空数据表内容
delete from 表名 where 条件; 删除满足条件的记录

delete from students;
delete from students where id=4;

逻辑删除表内容
添加is_delete字段将此字段设置为bit类型用0,1来表示是否删除
更新id_delete的值逻辑删除记录

alter table students add is_delete bit default 0;
update students set is_delete=1 where id=3;

MySQL 查询

查询

select 表名.字段, 表名.字段 from 表名; 此用法的意义在于表的别名
select 别名.字段, 别名.字段 from 表名 as 别名; 避免多个表同名冲突
select distinct 字段 from 表名; distinct 显示不同的 也就是去重

select students.name, students.name from students;
select s.name,s.name from students as s;
select distinct gender from students;
条件

比较运算符
< 小于 > 大于 <= 小于等于 >= 大于等于 != 不等于
逻辑运算符
andornot
select * from 表名 where not 条件1 and not 条件2; 查询不满足条件1也不满足条件2的结果
select * from 表名 where not (条件1 and 条件2); 查询不是满足条件1和条件2的结果

select * from students where not age>18 and not gender="女";
select * from students where not (age>18 and gender=2);

判断空
null 类似Python中的none 判断空使用 is null 而不是 == null
is null 为空 is not null 非空
select 字段 from 表名 where is null; 查询字段为空的结果
select 字段 from 表名 where is not null; 查询字段不为空的结果

slelect height from students where is null;
select height from students where is not null;

模糊查询
模糊查询效率低下因为需要匹配每一条记录的值
like 模糊匹配 % 没有或多个 _ 必须有一个
select 字段 from 表名 where 字段 like "小%"; 查询以小开头加多个任意字符的字段
select 字段 from 表名 where 字段 like "小_"; 查询以小开头一个任意字符的字段
select 字段 from 表名 where 字段 like "__"; 查询必须为两个字符的结果

select name from students where name like "小%";
select name from students where name like "小_";
select name from students where name like "__"

rlike 正则匹配
select 字段 from 表名 where 字段 rlike "^周.*"; 查询以周开头任意数量字符的结果
select 字段 from 表名 where 字段 rlike "杰$"; 查询必须以杰结尾的结果

select name from students where name rlike "^周.*";
select name from students where name rlike "杰$";

范围查询
select 字段 from 表名 where 字段 in(1,3,5); 包含集合的结果
select 字段 from 表名 where 字段 not in(2,4,6); 不包含集合的结果
连续范围
select 字段 from 表名 where 字段 between 开始 and 结束 在两个值范围的结果 包含开始和结束的值
select 字段 from 表名 where 字段 not between 开始 and 结束 不在范围内的结果 包含开始和结束的值

select name from students where cls in(1,3,5);
select name from students where cls not in(2,4,6);
排序

MySQL默认按主键小到大排序
指定排序后有相同值的继续按主键从小到大排序
asc 从小到大排序 desc 从大到小排序
select * from 表名 order by 字段 asc; 结果按照字段的值升序
select * from 表名 order by 字段 desc, 字段 desc; 当第一排序后有相同值时按第二排序继续排序

select * from students order by age desc;
select * from students order by age desc, id desc;
聚合函数

聚合函数就是用来输入多个数据输出一个结果的 在select 指定字段时使用
count() 统计个数 max() 求最大值 min() 求最小值 sum() 求和 avg() 求平均值 round(目标,位数) 四舍五入目标并指定保留小数
select count(字段) from 表名 where 条件; count()查询所指定字段出现的次数值为NULL的不统计
select max(字段) from 表名; max()取查询到的数据的最大值
select min(字段) from 表名; min()取查询到的数据的最小值
select sum(字段) from 表名; sum()求查询到的数据的总和
select avg(字段) from 表名; avg()求查询的数据的平均值 小数默认保留4位
select sum(字段)/count(*) from 表名; 通过计算获得平均值
select round(avg(字段),位数) from 表名; round(目标, 位数) 四舍五入 0不保留小数

select count(*) from students;
select max(age) from students;
select min(height) from students;
select sum(age) from students;
select avg(height) from students;
select sum(height)/count(*) from students;
select round(avg(age),2) from students;
分组

分组一般需要与聚合函数一起使用
group by 字段; 以此字段的记录为依据把表中的所有记录归纳分组生成一个中间表此表中此字段的值唯一其他字段的值可能有多个当语句中使用 group by 字段select 所查询的数据就只针对中间表内的数据进行查询所以 select 后只能输入此字段因为关系表不能输出有多个数据的记录 并且使用聚合函数进行操作 因为聚合函数可以接收多个数据 输出一个结果
where 指定表输出的条件 having 指定中间表输出的条件
count(字段) 查询表中此字段的数据以分组形式显示 原始表中null的不统计
group_concat(字段[,"char",字段]) 查询表中此字段的数据以分组形式显示 并且可以任意连接字符
select 字段 from 表名 group by 字段; 以字段分组 并查询分组后字段的信息 但不能查询其他字段的信息 因为其他字段可能有多个值
select count(字段) from 表名 group by gender; 查询每组性别分别有多少所统计的数量
select group_concat(字段,"-",字段) from 表名 group by gender; 查询每组性别中这些字段的值并以字符间隔

select gender from students group by gender;
select count(*) from students group by gender;
select gender, group_concat(name,"-",age) from students group by gender;
分页

面对大量数据时使用分页查看
limit 始终写在所有语句的最后
select 字段 from 表名 limit 个数; 限制查询的结果所显示的个数
select 字段 from 表名 limit 开始,个数; 指定结果的个数并且指定开始位置
select 字段 from 表名 limit (页码-1)*每页个数, 每页个数; 前端实现分页的原理 但SQL中不支持这种写法

select * from students limit 2;
select * from students limit 4, 2;
连接查询

MySQL中(仅限于MySQL)CROSS JOININNER JOIN的表现是一样的在INNER JOIN不指定ON条件得到的结果都是笛卡尔积 可以简写为 JOIN
having 指定中间表的查询条件
select * from 表1 inner join 表2; 查询字段以笛卡尔积输出结果
select 表1.* 表2.字段 from 表1 inner join 表2 on 表1.字段=表2.字段; 内连接查询字段显示表1字段等于表2字段的部分
select 别名1.字段, 别名2.字段 from 表1 as 别名1 left join 表2 as 别名2 on 别名1.字段=别名2.字段; 左链接查询 显示交集以左表为主
select 字段 from 表1 right join 表2 on 表1.字段=表2.字段; 右连接查询 显示交集 右表的数据如果左表没有对应的值用null填充

select * from students inner join classes on students.cls_id=classes.id;
select s.*, c.name from students as s inner join classes as c on s.cls_id=c.id;
select * from students left join classes on students.cls_id=classes.id;
select * from students left join classes on students.cls_id=classes.id having classes.name is null;
select students.name, classes_name from students right join classes on students.cls_id=classes.id;
自关联

如果在一个连接查询中 涉及到的两个表都是同一个表 这种查询就称为自连接查询
同一张表在FROM子句中多次出现 为了区别该表的每一次出现 需要为表定义一个别名 自连接是一种特殊的内连接 它是指相互连接的表在物理上为同一张表 但可以在逻辑上分为两张表
自关联可以实现 在一张表内存储包含关系的不同数据
select * from 表名 as 别名1 inner join 表名 as 别名2 on 别名1.字段=别名2.字段 having 别名1.字段="xxx"; 查询表中字段为xxx的所有自关联内容

子查询

子查询允许把一个查询嵌套在另一个查询当中 子查询 又叫内部查询 相对于内部查询包含内部查询的就称为外部查询
子查询中可以包含比如: select distinct group by order by limit join union 但是对应的外部查询必须是以下语句之一 select insert update delete set do
select * from 表 where 字段=(select 函数(字段) from 表); 通过内部查询的结果给定外部查询的范围

分组 聚合函数 自关联 子查询 综合运用

查询表中各种类中最贵商品的所有信息
select * from 表 inner join (select 字段, max(字段1) as 别名1 from 表 group by 字段) as 别名2 on 表.字段=别名2.别名1;

select * from goods as g1 inner join (select cata_name, max(price) as max_price from goods group by cate_name) as g2 on g1.price=g2.max_price;

视图

视图就是一条SELECT语句执行后返回的结果集
视图是查询语句执行的结果 不存储具体的数据

定义视图

建议以v_开头
create view 视图名称 as select 语句;

create view v_goods_b_c as select g.*, gb.name as brand_name, gc.name as cates_name from goods as g left join goods_brands as gb on g.brand_id=gb.id left join goods_cates as gc on g.cate_id=gc.id;
查看视图

show tables;查看表会列出所有视图

使用视图

视图的用途只是查询无法对视图进行增删改

select * from v_goods_b_c;
删除视图

drop view 视图名称;

drop view  v_goods_b_c;
视图的作用
  1. 提高了重用性 就像一个函数
  2. 数据库重构不影响程序的运行
  3. 提高了安全性能 可以对不同的用户
  4. 让数据更加清晰

事务

事务广泛的运用于订单系统 银行系统等多种场景

事务四大特性(简称ACID)

原子性(atomicity)

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性

一致性(consistency)

数据库总是从一个一致性的状态转换到另一个一致性的状态。(一致性确保了,因为事务最终没有提交,所做的修改也不会保存到数据库中。)

隔离性(isolation)

一个事务所做的修改在最终提交以前,对其他事务是不可见的。

持久性(durability)

一旦事务提交,则其所做的修改会永久保存到数据库。

事务命令

表的引擎类型必须是innodb类型才可以使用事务 这是mysql表的默认引擎
开启事务后执行修改命令 变更会维护到本地缓存中 而不维护到物理表中
开启事务
begin; 或者 start transaction;
将缓存中的数据变更维护到物理表中
commit;
放弃缓存中变更的数据
rollback;

注意

默认每条增删改命令都会自动的触发事务 包括insert update delete
在SQL语句中手动开启事务的原因是:可以进行多次数据的修改,如果成功一起成功,否则一起回滚到之前的数据

索引

当数据库中数据量很大时 查找数据会变得很慢 这时借助索引就可以让数据的查询变快
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。

索引原理

MySQL通过算法自动建立B-Tree 通过分叉缩小范围加速查询过程
最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段……这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。

索引的使用
  • 查看索引

    • show index from 表名;
  • 创建索引

    • create index 索引名称 on 表名(字段名称(长度))
    • 如果指定字段是字符串 需要指定长度 建议长度与定义字段时的长度一致
    • 字段类型如果不是字符串 可以不填写长度部分
create index name_index on goods(name(10));
  • 删除索引
    • drop index 索引名称 on 表名;
drop index name_index on goods;
注意:

要注意的是,建立太多的索引将会影响更新和插入的速度,因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序的开销不会很大,也没有必要建立另外的索引。

建立索引会占用磁盘空间

账户管理

在生产环境下操作数据库时,绝对不可以使用root账户连接,而是创建特定的账户,授予这个账户特定的操作权限,然后连接进行操作,主要的操作就是数据的crud

  • MySQL账户体系:

    • 服务实例级账号:如果某用户如root,拥有服务实例级分配的权限,那么该账号就可以删除所有的数据库、连同这些库中的表
    • 数据库级别账号:对特定数据库执行增删改查的所有操作
    • 数据表级别账号:对特定表执行增删改查等所有操作
    • 字段级别的权限:对某些表的特定字段进行操作
    • 存储程序级别的账号:对存储程序进行增删改查的操作
  • 账户的操作主要包括创建账户、删除账户、修改密码、授权权限等

1.进行账户操作时,需要使用root账户登录,这个账户拥有最高的实例级权限
2.通常都使用数据库级操作权限

数据库设计

  • 关系型数据库建议在E-R模型的基础上,我们需要根据产品经理的设计策划,抽取出来模型与关系,制定出表结构,这是项目开始的第一步
  • 在开发中有很多设计数据库的软件,常用的如power designer,db desinger等,这些软件可以直观的看到实体及实体间的关系
  • 设计数据库,可能是由专门的数据库设计人员完成,也可能是由开发组成员完成,一般是项目经理带领组员来完成
  • 现阶段不需要独立完成数据库设计,但是要注意积累一些这方面的经验

三范式

  • 经过研究和对使用中问题的总结,对于设计数据库提出了一些规范,这些规范被称为范式(Normal Form)
  • 目前有迹可寻的共有8种范式,一般需要遵守3范式即可
  • 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。

考虑这样一个表:【联系人】(姓名,性别,电话) 如果在实际场景中,一个联系人有家庭电话和公司电话,那么这种表结构设计就没有达到 1NF。要符合 1NF 我们只需把列(电话)拆分,即:【联系人】(姓名,性别,家庭电话,公司电话)。1NF 很好辨别,但是 2NF 和 3NF 就容易搞混淆。

  • 第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。

考虑一个订单明细表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。 因为我们知道在一个订单中可以订购多种产品,所以单单一个 OrderID 是不足以成为主键的,主键应该是(OrderID,ProductID)。显而易见 Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID。所以 OrderDetail 表不符合 2NF。不符合 2NF 的设计容易产生冗余数据。
可以把【OrderDetail】表拆分为【OrderDetail】(OrderID,ProductID,Discount,Quantity)和【Product】(ProductID,UnitPrice,ProductName)来消除原订单表中UnitPrice,ProductName多次重复的情况。

  • 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。

考虑一个订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID)。 其中 OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 等非主键列都完全依赖于主键(OrderID),所以符合 2NF。不过问题是 CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。 通过拆分【Order】为【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到 3NF。 *第二范式(2NF)和第三范式(3NF)的概念很容易混淆,区分它们的关键点在于,2NF:非主键列是否完全依赖于主键,还是依赖于主键的一部分;3NF:非主键列是直接依赖于主键,还是直接依赖于非主键列。

E-R模型
  • E表示entry,实体,设计实体就像定义一个类一样,指定从哪些方面描述对象,一个实体转换为数据库中的一个表
  • R表示relationship,关系,关系描述两个实体之间的对应规则,关系的类型包括包括一对一、一对多、多对多
  • 关系也是一种数据,需要通过一个字段存储在表中

实体A对实体B为1对1,则在表A或表B中创建一个字段,存储另一个表的主键值
实体A对实体B为1对多:在表B中创建一个字段,存储表A的主键值
实体A对实体B为多对多:新建一张表C,这个表只有两个字段,一个用于存储A的主键值,一个用于存储B的主键值

扩展阅读
  • 看看别人家设计的规范
  • 58到家数据库30条军规解读
逻辑删除
  • 对于重要数据,并不希望物理删除,一旦删除,数据无法找回
  • 删除方案:设置isDelete的列,类型为bit,表示逻辑删除,默认值为0
  • 对于非重要数据,可以进行物理删除
  • 数据的重要性,要根据实际开发决定

你可能感兴趣的:(MySQL)