数据库的三范式是关系型数据库设计中的规范,用于减少冗余数据,提高数据存储的效率和数据的一致性。三范式分为以下三个层次:
第一范式(1NF): 数据表中的所有字段都是不可再分的原子值,每一列都是原子的,不可再分。
第二范式(2NF): 在1NF的基础上,非主键列完全依赖于主键,而不是依赖于主键的一部分。
第三范式(3NF): 在2NF的基础上,非主键列之间互不依赖,即不存在传递依赖。
下面是一个简单的示例来说明三范式的概念:
考虑一个包含订单和订单项的数据库表设计:
不符合第一范式的设计:
-- 订单表
CREATE TABLE Orders (
order_id INT PRIMARY KEY,
customer_name VARCHAR(100),
order_date DATE,
items VARCHAR(255)
);
-- 数据示例
INSERT INTO Orders (order_id, customer_name, order_date, items)
VALUES (1, 'John Doe', '2022-01-01', 'Item1,Item2,Item3');
在上述设计中,items
列包含了多个商品,不符合第一范式,因为每一列不是原子的。
符合第一范式的设计:
-- 订单表
CREATE TABLE Orders (
order_id INT PRIMARY KEY,
customer_name VARCHAR(100),
order_date DATE
);
-- 订单项表
CREATE TABLE OrderItems (
item_id INT PRIMARY KEY,
order_id INT,
item_name VARCHAR(50),
quantity INT,
price DECIMAL(10, 2),
FOREIGN KEY (order_id) REFERENCES Orders(order_id)
);
-- 数据示例
-- 订单
INSERT INTO Orders (order_id, customer_name, order_date)
VALUES (1, 'John Doe', '2022-01-01');
-- 订单项
INSERT INTO OrderItems (item_id, order_id, item_name, quantity, price)
VALUES (1, 1, 'Item1', 2, 10.00),
(2, 1, 'Item2', 1, 15.00),
(3, 1, 'Item3', 3, 8.00);
在这个设计中,订单和订单项被拆分为两个表,每一列都是原子的。
符合第二范式的设计:
在上述设计中,已经符合第二范式,因为每个表中的非主键列完全依赖于主键。
不符合第三范式的设计:
-- 订单表
CREATE TABLE Orders (
order_id INT PRIMARY KEY,
customer_id INT,
customer_name VARCHAR(100),
order_date DATE,
customer_email VARCHAR(100)
);
-- 数据示例
INSERT INTO Orders (order_id, customer_id, customer_name, order_date, customer_email)
VALUES (1, 101, 'John Doe', '2022-01-01', 'john@example.com');
在这个设计中,customer_name
和 customer_email
之间存在传递依赖,因为 customer_email
可以通过 customer_id
推导得到。为了符合第三范式,需要将这两列分离到独立的表中。
符合第三范式的设计:
-- 顾客表
CREATE TABLE Customers (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(100),
customer_email VARCHAR(100)
);
-- 订单表
CREATE TABLE Orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES Customers(customer_id)
);
-- 数据示例
-- 顾客
INSERT INTO Customers (customer_id, customer_name, customer_email)
VALUES (101, 'John Doe', 'john@example.com');
-- 订单
INSERT INTO Orders (order_id, customer_id, order_date)
VALUES (1, 101, '2022-01-01');
在这个设计中,将 customer_name
和 customer_email
分离到了独立的 Customers
表中,消除了传递依赖。