数据库之十 三大范式

2024-02-01 01:44
文章标签 三大 数据库 范式 之十

本文主要是介绍数据库之十 三大范式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【零】序

【1】范式分类

  • 数据库范式中,最为人所知的有三大范式(1NF2NF3NF
  • 但除此之外也有一些其他设计规范,如第四范式(4NF)、第五范式:完美范式(5NF)、巴斯-科德范式(BCNF)以及反范式设计。

【2】三大范式

  • 范式(Normal Form)是设计数据库时要遵守的一些原则。
  • 数据库的三大范式递进的关系,也就是后续的范式都基于前一个范式的基础上推行。比如,第二范式必须建立在第一范式的基础之上,如果设计的库表第一范式都不满足,那定然是无法满足第二范式的。

【一】第一范式(1NF

【1】说明

  • 原子性原子性原子性

  • 即每一列都是不可分割的原子数据项

【2】举例

(1)改前
  • 让我们来看看这个订单表
# 创建表
drop table if exists order_form;
create table if not exists order_form(
order_id int auto_increment primary key,
user_info varchar(255),
goods_info varchar(255),
order_info varchar(255),
total_prices float
);
# 插入数据
insert order_form(user_info, goods_info, order_info, total_prices) values
('bruce, beijing', 'phone, 1200', '5, 2022-12-12', 6000),
('tom, shanghai', 'computer, 5555', '10, 2022-12-15', 55550),
('lily, shanghai', 'laptop, 1000', '11, 2022-11-15', 11000),
('lala, beijing', 'phone, 1200', '8, 2022-12-15', 9600),
('lany, shanghai', 'computer, 5555', '6, 2022-11-15', 33330);
  • 查看表内容
select * from order_form;
+----------+----------------+----------------+----------------+--------------+
| order_id | user_info      | goods_info     | order_info     | total_prices |
+----------+----------------+----------------+----------------+--------------+
|        1 | bruce, beijing | phone, 1200    | 5, 2022-12-12  |         6000 |
|        2 | tom, shanghai  | computer, 5555 | 10, 2022-12-15 |        55550 |
|        3 | lily, shanghai | laptop, 1000   | 11, 2022-11-15 |        11000 |
|        4 | lala, beijing  | phone, 1200    | 8, 2022-12-15  |         9600 |
|        5 | lany, shanghai | computer, 5555 | 6, 2022-11-15  |        33330 |
+----------+----------------+----------------+----------------+--------------+
  • 在这个数据表中,很明显可以看出来
    • 用户信息为什么要写在一起呢,完全可以分开写
    • user_info这个字段拆写成user_nameuser_address
    • 同理商品信息的东西也没必要写在一起
    • goods_info这个字段拆写成goods_namegoods_price
    • 同理订单信息也是的
    • order_info这个字段拆写成order_numorder_time
(2)改后
  • 按照原子性要求,重新创建表
drop table if exists order_form;
create table if not exists order_form(
order_id int auto_increment primary key,
user_name varchar(255),
user_address varchar(255),
goods_name varchar(255),
goods_price float,
order_num int,
order_date date,
total_prices float
);
  • 重新插入数据
insert into order_form(user_name, user_address, goods_name, goods_price, order_num, order_date, total_prices) VALUES
('bruce', 'beijing', 'phone', 1200, 5, '2022-12-12', 6000),
('tom', 'shanghai', 'computer', 5555, 10, '2022-12-15', 55550),
('lily', 'shanghai', 'laptop', 1000, 11, '2022-11-15', 11000),
('lala', 'beijing', 'phone', 1200, 8, '2022-12-15', 9600),
('lany', 'shanghai', 'computer', 5555, 6, '2022-11-15', 33330);
  • 查看数据
+----------+-----------+--------------+------------+-------------+-----------+------------+--------------+
| order_id | user_name | user_address | goods_name | goods_price | order_num | order_date | total_prices |
+----------+-----------+--------------+------------+-------------+-----------+------------+--------------+
|        1 | bruce     | beijing      | phone      |        1200 |         5 | 2022-12-12 |         6000 |
|        2 | tom       | shanghai     | computer   |        5555 |        10 | 2022-12-15 |        55550 |
|        3 | lily      | shanghai     | laptop     |        1000 |        11 | 2022-11-15 |        11000 |
|        4 | lala      | beijing      | phone      |        1200 |         8 | 2022-12-15 |         9600 |
|        5 | lany      | shanghai     | computer   |        5555 |         6 | 2022-11-15 |        33330 |
+----------+-----------+--------------+------------+-------------+-----------+------------+--------------+
  • 这样就满足了原子性要求,看着也舒服了很多

【二】第二范式(2NF

【1】说明

  • 完全依赖完全依赖完全依赖

  • 第二范式要求在第一范式的基础上,表中的每一列都必须完全依赖于全部主键,而不是部分主键

【2】举例

(1)改前分析
  • 上面的第一范式还是很好理解的
  • 我们在分析分析这个第二范式
  • 在这个订单表中,用户的地址和订编号是完全依赖的吗
    • 看这并不需要,我们订单锁定用户名字就可以了
  • 同理商品信息呢,也是一样的
  • 所以我们可以创建三个表
    • 用户表:用户id,用户名字,用户地址
    • 商品表:商品id, 商品名字,商品价格
    • 订单表:订单id,用户id,商品id,商品数量,总价格
(2)改后
  • 按照完全依赖性要求,重新创建表
# 订单表
drop table if exists orders;
create table if not exists orders (order_id int auto_increment primary key,user_id int,goods_id int,order_num int,order_date date,total_prices float
);
# 用户表
drop table if exists users;
create table if not exists users (user_id int auto_increment primary key,user_name varchar(255),user_address varchar(255)
);
# 商品表
drop table if exists goods;
create table if not exists goods (goods_id int auto_increment primary key,goods_name varchar(255),goods_price float
);
  • 将原来的内容去重插入新表
# 用户表
insert into users(user_name, user_address) 
select distinct user_name, user_address from order_form;
# 商品表
insert into goods(goods_name, goods_price) 
select distinct goods_name, goods_price from order_form;
# 订单表
insert into orders(user_id, goods_id, order_num, order_date, total_prices) 
select users.user_id, goods.goods_id, order_form.order_num, order_form.order_date, order_form.total_prices 
from order_form 
join users on order_form.user_name = users.user_name and order_form.user_address = users.user_address 
join goods on order_form.goods_name = goods.goods_name and order_form.goods_price = goods.goods_price;
  • 查看数据
select * from users;
# 用户表
+---------+-----------+--------------+
| user_id | user_name | user_address |
+---------+-----------+--------------+
|       1 | bruce     | beijing      |
|       2 | tom       | shanghai     |
|       3 | lily      | shanghai     |
|       4 | lala      | beijing      |
|       5 | lany      | shanghai     |
+---------+-----------+--------------+
select * from goods;
# 商品表
+----------+------------+-------------+
| goods_id | goods_name | goods_price |
+----------+------------+-------------+
|        1 | phone      |        1200 |
|        2 | computer   |        5555 |
|        3 | laptop     |        1000 |
+----------+------------+-------------+
select * from orders;
# 订单表
+----------+---------+----------+-----------+------------+--------------+
| order_id | user_id | goods_id | order_num | order_date | total_prices |
+----------+---------+----------+-----------+------------+--------------+
|        1 |       1 |        1 |         5 | 2022-12-12 |         6000 |
|        2 |       2 |        2 |        10 | 2022-12-15 |        55550 |
|        3 |       3 |        3 |        11 | 2022-11-15 |        11000 |
|        4 |       4 |        1 |         8 | 2022-12-15 |         9600 |
|        5 |       5 |        2 |         6 | 2022-11-15 |        33330 |
+----------+---------+----------+-----------+------------+--------------+
  • 以上内容就满足第二范式的完全依赖要求

【三】第三范式(3NF

【1】说明

  • 非传递依赖非传递依赖非传递依赖

  • 表中的每一列都必须直接依赖于主键,而不能传递依赖

【2】举例

(1)改前
  • 再让我们看看订单表
select * from orders;
# 订单表
+----------+---------+----------+-----------+------------+--------------+
| order_id | user_id | goods_id | order_num | order_date | total_prices |
+----------+---------+----------+-----------+------------+--------------+
|        1 |       1 |        1 |         5 | 2022-12-12 |         6000 |
|        2 |       2 |        2 |        10 | 2022-12-15 |        55550 |
|        3 |       3 |        3 |        11 | 2022-11-15 |        11000 |
|        4 |       4 |        1 |         8 | 2022-12-15 |         9600 |
|        5 |       5 |        2 |         6 | 2022-11-15 |        33330 |
+----------+---------+----------+-----------+------------+--------------+
  • total_price字段,这个字段是goods_price(在goods表中)和orders表的order_num的乘积。
  • 这样,total_price就会依赖于非主键字段goods_priceorder_num,违反第三范式。
(2)改后
  • 这里的修改很简单

  • 为了满足第三范式,我们直接移除这个total_price字段姐可以

  • 毕竟它可以通过其他字段得出

alter table orders drop column total_prices;
  • 重新查看订单表
+----------+---------+----------+-----------+------------+
| order_id | user_id | goods_id | order_num | order_date |
+----------+---------+----------+-----------+------------+
|        1 |       1 |        1 |         5 | 2022-12-12 |
|        2 |       2 |        2 |        10 | 2022-12-15 |
|        3 |       3 |        3 |        11 | 2022-11-15 |
|        4 |       4 |        1 |         8 | 2022-12-15 |
|        5 |       5 |        2 |         6 | 2022-11-15 |
+----------+---------+----------+-----------+------------+
  • 这样所有的表就都满足了三大范式要求

【四】总结

【1】三大范式

  1. 第一范式(1NF):
    • 确保原子性
    • 每一列都是不可分割的原子数据项
  2. 第二范式(2NF):
    • 确保完全依赖
    • 每一列都必须完全依赖于全部主键
  3. 第三范式(3NF):
    • 确保非传递依赖
    • 每一列都必须直接依赖于主键

【2】必要性讨论

  • 虽然遵循三范式的数据库设计可能会导致表的数量增加,但这并不意味着设计过程更加复杂或麻烦。实际上,如果不遵循这些范式,可能会导致以下问题:

    1. 数据冗余:如果不遵循范式,一张表可能包含大量重复的数据。
    2. 表结构臃肿:如果一张表包含多种业务属性,那么这张表可能会变得非常大,不易于操作和管理。
    3. 更新困难:如果表中的数据存在依赖关系,那么更新一部分数据可能需要修改大量的记录。
  • 因此,遵循三范式的数据库设计可以使表结构更加优雅,提高数据库的灵活性和可维护性。

这篇关于数据库之十 三大范式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/665705

相关文章

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

mysql数据库重置表主键id的实现

《mysql数据库重置表主键id的实现》在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,本文主要介绍了mysql数据库重置表主键id的实现,具有一定的参考价值,感兴趣的可以了... 目录关键语法演示案例在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,当我们

Spring Boot 整合 MyBatis 连接数据库及常见问题

《SpringBoot整合MyBatis连接数据库及常见问题》MyBatis是一个优秀的持久层框架,支持定制化SQL、存储过程以及高级映射,下面详细介绍如何在SpringBoot项目中整合My... 目录一、基本配置1. 添加依赖2. 配置数据库连接二、项目结构三、核心组件实现(示例)1. 实体类2. Ma

查看Oracle数据库中UNDO表空间的使用情况(最新推荐)

《查看Oracle数据库中UNDO表空间的使用情况(最新推荐)》Oracle数据库中查看UNDO表空间使用情况的4种方法:DBA_TABLESPACES和DBA_DATA_FILES提供基本信息,V$... 目录1. 通过 DBjavascriptA_TABLESPACES 和 DBA_DATA_FILES

Java实现数据库图片上传与存储功能

《Java实现数据库图片上传与存储功能》在现代的Web开发中,上传图片并将其存储在数据库中是常见的需求之一,本文将介绍如何通过Java实现图片上传,存储到数据库的完整过程,希望对大家有所帮助... 目录1. 项目结构2. 数据库表设计3. 实现图片上传功能3.1 文件上传控制器3.2 图片上传服务4. 实现

使用Dify访问mysql数据库详细代码示例

《使用Dify访问mysql数据库详细代码示例》:本文主要介绍使用Dify访问mysql数据库的相关资料,并详细讲解了如何在本地搭建数据库访问服务,使用ngrok暴露到公网,并创建知识库、数据库访... 1、在本地搭建数据库访问的服务,并使用ngrok暴露到公网。#sql_tools.pyfrom

Java实现数据库图片上传功能详解

《Java实现数据库图片上传功能详解》这篇文章主要为大家详细介绍了如何使用Java实现数据库图片上传功能,包含从数据库拿图片传递前端渲染,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、数据库搭建&nbsChina编程p; 3、后端实现将图片存储进数据库4、后端实现从数据库取出图片给前端5、前端拿到

IDEA连接达梦数据库的详细配置指南

《IDEA连接达梦数据库的详细配置指南》达梦数据库(DMDatabase)作为国产关系型数据库的代表,广泛应用于企业级系统开发,本文将详细介绍如何在IntelliJIDEA中配置并连接达梦数据库,助力... 目录准备工作1. 下载达梦JDBC驱动配置步骤1. 将驱动添加到IDEA2. 创建数据库连接连接参数

Jmeter如何向数据库批量插入数据

《Jmeter如何向数据库批量插入数据》:本文主要介绍Jmeter如何向数据库批量插入数据方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Jmeter向数据库批量插入数据Jmeter向mysql数据库中插入数据的入门操作接下来做一下各个元件的配置总结Jmete

MySql中的数据库连接池详解

《MySql中的数据库连接池详解》:本文主要介绍MySql中的数据库连接池方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql数据库连接池1、概念2、为什么会出现数据库连接池3、原理4、数据库连接池的提供商5、DataSource数据源6、DBCP7、C