1 数据库设计范式
-
第一范式
保持每个字段的原子性,每列存储单一值,非数组、集合
每行必须有唯一标识,即主键 -
第二范式
表必须满足范式一
不要在以复合主键为主键的表格里存放只依赖复合主键中单一主键的字段
- 举例
订单明细表:
order_id | product_id | product_name | quantity |
---|---|---|---|
100 | 1 | iPhone | 2 |
100 | 2 | MacBook | 1 |
200 | 1 | iPhone | 3 |
一份订单必然包含订单ID、对应产品ID,二者组成复合主键,绑定对应产品数量,即达成第二范式:非主键字段(quantity)完全依赖主键
但product_name只依赖product_id,不构成完全依赖复合主键,造成存储的数据冗余。
因此将构成完全依赖的主键与非主键提取出来,做成一个单独的表格
如:
订单明细表(仅存储依赖复合主键的字段):
order_id | product_id | quantity |
---|---|---|
100 | 1 | 2 |
商品表(独立存储商品信息):
product_id | product_name |
---|---|
1 | iPhone |
-
第三范式
表必须满足第二范式
非主键字段之间不能有传递依赖(即非主键列不能依赖于其他非主键列)。
其实就是第二范式的变种,也是要求非主键字段必须完全依赖主键
- 举例
❌ 违反3NF的表(department_location
依赖于department_id
,而非直接依赖主键employee_id
)
员工表:
employee_id | name | department_id | department_location |
---|---|---|---|
1 | Alice | 10 | New York |
✅ 符合3NF的设计:
员工表(仅存储直接依赖主键的字段):
employee_id | name | department_id |
---|---|---|
1 | Alice | 10 |
部门表(独立存储部门信息):
department_id | department_location |
---|---|
10 | New York |
总结:第二、三范式的本质要求就是避免在多余的列内存储冗余数据,保证主键(单一主键/复合主键)和非主键字段的完全依赖与唯一性,就是根据主键对应过去的非主键字段值必然是唯一的。
违反二三范式的其他后果:
- 更新异常:更新iPhone——>Huawei时,订单表也要随之更新,易发生操作遗漏
- 插入异常:如果商品iPhone没有被购买,就无法存储,因为他依赖包含
order_id
在内的复合主键。
2 开启外键约束
外键功能默认关闭:
SQLite
默认禁用外键约束(为了兼容旧版本),需先启用:
PRAGMA foreign_keys = ON;
-- 在每次连接时执行
每次使用数据库连接时,都需要手动开启外键约束,这样在插入、更新或删除数据时,SQLite 才会自动检查外键约束