第一范式
1,表中所有字段只具有单一属性;address既包含了省市区 河南-郑州-高新区 2,单一属性的列由基本的数据类型构成; 3,设计出的表为二维表;
第二范式
要求一个表中只具有一个业务主键;即符合第二范式的表中不能存在非主键列只对部分主键的依赖关系,(业务主键可能包含一个列或多个列)。通常表现在复合主键的情况下,部分字段,不依赖复合主键中的某一个
以电商网站示例
1,商品管理功能
修改前==> 商品信息表(商品名称、商品分类名称、商品描述、商品价格)
业务主键(商品名称、商品分类名称)
此时如何做到新增分类;(而商品后续添加)
修改后==> 商品信息(商品名称、商品描述、商品价格等)
分类信息(商品分类名称,分类描述)
商品分类关系表(商品名称、商品分类名称)
goods | CREATE TABLE `goods` (
`g_name` varchar(20) DEFAULT NULL,
`g_desc` varchar(100) DEFAULT NULL,
`g_price` decimal(10,3) DEFAULT NULL,
`g_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`g_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |
category | CREATE TABLE `category` (
`c_name` varchar(20) DEFAULT NULL,
`c_desc` varchar(100) DEFAULT NULL,
`c_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
gcrelation | create table gcrelation(g_id int unsigned,c_id int unsigned,
foreign key(g_id) references goods(g_id),
foreign key(c_id) references category(c_id));
-------------------------------------------------------------
a,删除商品 商品分类关系表得删除
a-1,先删除中间表,再删除商品表
b,删除分类
同上
c,增加
先增加商品或分类,再增加关联关系
d,修改
只修改商品表、分类表,不牵扯到中间表
e,查
e-1,某分类下的所有商品
select a.* from goods a left join gcrelation b on a.g_id = b.g_id where b.c_id = 1;
select * from goods where g_id in (select g_id from gcrelation where c_id = 1);
e-2,各个分类下有多少商品
select count(b.c_id),a.c_name,a.c_id,b.c_id from category a left join gcrelation b on a.c_id = b.c_id group by a.c_id;
e-3,查询所有的商品既所属的分类信息
select a.g_name,a.g_price,c_name from goods a left join gcrelation b on a.g_id = b.g_id left join category c on b.c_id = c.c_id;
反范式设计:
冗余有时是必要的。
将中间表商品分类关系表移除,将商品分类名称(分类ID)添加至商品信息表,商品分类ID,作为商品表对分类表的外键
note :关系由谁来维护
一般的情况下-> 关系在多的一端进行维护
第三范式
每一个非主属性既不部分依赖于也不传递依赖于业务主键,即在第二范式的基础上消除了非主属性对主键的传递依赖、
比如学生信息表 sno,sname,birth_date,depart_name,depart_addr,depart_tel (sno为primary key) sno 得到学生所在的院系depart_name, depart_name可以得到depart_addr,depart_tel等信息 得将学生信息表拆分为两张表 2,订单相关功能 修改前==> 订单表(订单编号[primarykey],用户名,订单日期,订单金额,订单商品分类,订单商品名,订单商品单价, 订单商品数量,支付金额,物流单号) 此时订单编号 -> 订单商品->订单商品数量->订单商品单价,订单金额 不符合第三范式 修改后==> 订单表a(订单编号,用户名,订单日期,支付金额,物流单号) 订单商品关联表b(订单编号,订单商品名称,订单商品分类名称,订单数量) 商品信息表d(商品名称、商品分类名称、商品描述、商品价格) 商品分类关联表c 需求一,计算用户订单总金额(关联表越多,性能越差) select 用户名,sum(d.订单商品单价*b.订单商品数量) from 订单表 a join 订单商品关联表 b on a.订单编号 = b.订单编号 join on 商品分类关联表 c on c.商品名称 = b.商品名称 and c.分类名称 = b.订单商品分类名称 join 商品信息表 d on d.商品名称 = c.商品名称 group by 订单用户 问题,双11促销,价格波动,得重新进行价格关联,而且还要记录历史价格 需求二,查询下单用户和订单详情 还得关联用户信息表 此时都已经涉及了5张表 反范式设计: 订单表中添加用户信息比如(手机号[用户的任何凭证],订单金额) -> 方便直接查询订单用户信息 订单商品关联表添加商品表中的(商品单价信息) 反范式后的需求一: select 用户凭证信息,sum(订单金额) from 订单表 group by 用户凭证
3,层级类型树表的处理
部门表
权限表
菜单表
book表
name,p_id(父级目录)
-----------------------------------------------------------------
| CREATE TABLE `books` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`p_id` int(10) unsigned DEFAULT NULL COMMENT '上级目录',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 |
------+-------+-------------------------------------------------
书籍信息
书名
章节名
小节
标题
MySQL
初始MySQl
MySQL的安装
windows的安装
linux的安装
MySQL语法
insert的使用
select的使用
Java
mysql>
SELECT
a.name AS ONE,
b.name AS two,
c.name AS three,
d.name AS four
FROM
books a
LEFT JOIN books b
ON a.id = b.p_id
LEFT JOIN books c
ON b.id = c.p_id
LEFT JOIN books d
ON c.id = d.p_id
WHERE a.p_id = 0;
+----------------+-----------+--------------+---------------+
| one | two | three | four |
+----------------+-----------+--------------+---------------+
| MySQL | 初识MySQL | MySQL的安装 | windows的安装 |
| MySQL | 初识MySQL | MySQL的安装 | linux的安装 |
| MySQL | MySQL语法 | insert的使用 | NULL |
| MySQL | MySQL语法 | select的使用 | NULL |
| ThinkingInJava | NULL | NULL | NULL |
+----------------+-----------+--------------+---------------+
5 rows in set (0.00 sec)