概念
在关系型数据库中,主键(Primary Key)是用来唯一标识数据库表中的每条记录(行)的一个或多个列。主键具有以下特点:
-
唯一性:主键的值在整个表中必须是唯一的,每个记录都必须具有唯一的主键值。
-
非空性:主键的值不能为空,即主键列不能包含 NULL 值。
-
不可更改性:主键值在记录被创建后不能更改,确保了主键的持久性。
通过定义主键,可以确保表中的每条记录都可以被唯一标识和引用。主键通常用于支持表之间的关联关系和数据的完整性约束。
候选键(Candidate Key)是在关系表中可以作为主键的潜在列或组合列集合。与主键相比,候选键也具有唯一性和非空性的特性,但可以有多个候选键存在。候选键的选择通常取决于业务需求和数据的语义。
一个表可以有多个候选键,但只能有一个主键。从候选键中选择主键时,需要选择最适合标识和引用记录的键。一般而言,主键应该满足简洁性、稳定性和可理解性的要求。
下面是一个示例,说明主键和候选键的概念:
考虑一个学生表(Student),包含学生学号、姓名和电子邮件地址。在这个表中,学生学号可以作为主键,因为它是唯一的且不可为空。同时,姓名和电子邮件地址也具有唯一性,它们可以作为候选键,但最终选择学生学号作为主键。
| 学号 | 姓名 | 电子邮件 |
|---|---|---|
| 1001 | Alice | alice@example.com |
| 1002 | Bob | bob@example.com |
| 1003 | Carol | carol@example.com |
在上述示例中,学号列是主键,因为它能够唯一标识每个学生。候选键是指可以选择作为主键的潜在列或列集合,这里的候选键是姓名和电子邮件地址。
ACID
数据库的ACID特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
-
原子性(Atomicity):原子性要求数据库操作要么全部执行成功,要么完全不执行,即具有 “全还是不还” 的特性。如果一个事务中的任何一个操作失败,那么整个事务将被回滚到最初状态,所有已经执行的操作都将被撤销。
-
一致性(Consistency):一致性确保数据库在进行事务处理前后始终保持一致的状态。这意味着事务执行后,数据库中的数据必须满足预定义的完整性约束和业务规则,不会破坏数据的一致性。
-
隔离性(Isolation):隔离性确保并发执行的事务相互之间是隔离的,一个事务的操作不会被其他事务看到,直到事务提交完成。这可以防止并发执行的事务相互干扰或产生不一致的结果。
-
持久性(Durability):持久性要求一旦事务提交成功,其所做的修改将永久保存在数据库中,并且对于系统故障或崩溃也不会丢失。即使在系统发生故障后进行恢复,已提交的事务的结果也应该能够保持持久。
一致性
让我们以一个银行转账的例子来解释一致性。
假设一个用户在银行账户A中有1000美元,另一个用户在账户B中有500美元。现在,用户A要向用户B转账200美元。这个转账过程可以表示为一个事务。
在一致性的情况下,以下几个条件满足:
-
初始状态:账户A的余额为1000美元,账户B的余额为500美元。
-
转账过程:用户A发起转账请求,银行系统首先会检查账户A是否有足够的余额(1000美元),然后将账户A的余额减去200美元,账户B的余额增加200美元。
-
最终状态:转账完成后,账户A的余额应为800美元,账户B的余额应为700美元。
在一致性的情况下,转账过程必须满足预定义的完整性规则和业务规则。例如,不允许出现账户余额为负数或非法转账金额的情况。
如果一致性无法得到保证,可能会出现以下情况之一:
-
转账金额超过了账户A的余额,但转账仍然执行成功,导致账户A的余额为负数。
-
转账过程中出现了系统故障或中断,导致账户A的余额减少,但账户B的余额没有增加,造成不一致的状态。
一致性确保在任何情况下,转账过程都满足预期的规则和约束,不会导致数据的不一致或破坏数据的完整性。
完整性
在数据库中,有一些重要的规则和约束被用来确保数据的完整性、一致性和准确性。下面是一些常见的数据库规则:
-
实体完整性(Entity Integrity):实体完整性要求每个表必须有一个主键,且主键值不能为空(非空)。这确保了表中的每个实体都具有唯一标识,并且每个实体都可以被唯一地识别和引用。
-
参照完整性(Referential Integrity):参照完整性用于维护表之间的关系。通过定义外键和参照关系,可以确保在引用其他表中的数据时,被引用的值必须存在于被引用的表中。这防止了无效的引用和不一致的数据关系。
-
用户定义的完整性(User-defined Integrity):用户定义的完整性允许开发者根据特定的业务需求定义自定义的规则和约束。这可以通过触发器(Triggers)、存储过程(Stored Procedures)和校验约束(Check Constraints)等机制来实现。用户定义的完整性确保满足特定领域或应用程序的特殊要求。
这些规则和约束是数据库中的一些基本原则,用于确保数据的完整性、一致性和准确性。它们帮助维护数据库的结构和数据的正确性,提供了一种有效的方式来管理和保护数据。
范式
数据库范式是一组规则,用于设计关系型数据库中的表结构,以减少数据冗余和提高数据一致性。范式分为不同级别,通常有第一范式(1NF)、第二范式(2NF)、第三范式(3NF)等。以下是各个范式的简要介绍,并辅以一个示例:
- 第一范式(1NF):要求每个数据表中的每个列都是原子的,不可再分的。也就是说,每个列中的数据不应包含多个值或重复的值。
示例:考虑一个学生表(Student),包含学生的学号、姓名和选修课程。在第一范式下,每个列应该只包含单个值,不应该有多个值的情况。因此,如果一个学生选修多门课程,应该将每门课程放在一个独立的记录中,而不是将所有课程放在一个单独的列中。
| 学号 | 姓名 | 选修课程 |
|---|---|---|
| 1 | Alice | Math, CS |
| 2 | Bob | Math, Art |
- 第二范式(2NF):在满足第一范式的基础上,要求每个非主键列完全依赖于整个主键,而不是仅依赖于主键的一部分。
示例:考虑一个订单表(Order),包含订单号、产品号、产品名称和产品价格。在第二范式下,如果产品名称和产品价格只与产品号相关,而不依赖于订单号,则应将产品相关的信息拆分为一个独立的表。
订单表(Order):
| 订单号 | 产品号 | 产品名称 | 产品价格 |
|---|---|---|---|
| 1 | 1 | Apple | $1 |
| 1 | 2 | Orange | $2 |
| 2 | 1 | Apple | $1 |
产品表(Product):
| 产品号 | 产品名称 | 产品价格 |
|---|---|---|
| 1 | Apple | $1 |
| 2 | Orange | $2 |
- 第三范式(3NF):在满足第二范式的基础上,要求非主键列之间不存在传递依赖关系。换句话说,非主键列应该只依赖于主键,而不依赖于其他非主键列。
示例:考虑一个员工表(Employee),包含员工号、部门号、部门名称和部门负责人。在第三范式下,部门名称和部门负责人应该从部门表中提取出来,而不是在员工表中重复存储。
员工表(Employee):
| 员工号 | 部门号 | 部门名称 | 部门负责人 |
|---|---|---|---|
| 1 | 101 | Sales | Alice |
| 2 | 102 | Marketing | Bob |
部门表(Department):
| 部门号 | 部门名称 | 部门负责人 |
|---|---|---|
| 101 | Sales | Alice |
| 102 | Marketing | Bob |
这是一个简化的示例,实际的数据库设计可能涉及更多表和关系。范式的目标是通过规范化数据结构,减少数据冗余、提高数据一致性和查询性能。但需要注意,在某些情况下,过度范式化可能导致数据查询复杂性增加,因此需要在设计数据库时进行权衡和优化。
- BCNF(Boyce-Codd范式):BCNF是一种更高级的范式,它要求每个非主键列完全依赖于候选键(包括主键),而不是仅依赖于部分候选键。
示例:考虑一个供应商表(Supplier),包含供应商编号、产品编号和产品价格。假设一个供应商可以提供多种产品,但每个产品只能由一个供应商提供。在这种情况下,如果供应商编号和产品价格只依赖于产品编号,而不依赖于供应商编号,那么应该将供应商相关的信息拆分为一个独立的表。
供应商表(Supplier):
| 供应商编号 | 产品编号 | 产品价格 |
|---|---|---|
| 1 | 1 | $10 |
| 1 | 2 | $20 |
| 2 | 1 | $15 |
产品表(Product):
| 产品编号 | 产品名称 |
|---|---|
| 1 | Apple |
| 2 | Orange |
供应商产品表(SupplierProduct):
| 供应商编号 | 产品编号 | 产品价格 |
|---|---|---|
| 1 | 1 | $10 |
| 1 | 2 | $20 |
| 2 | 1 | $15 |
BCNF范式消除了非主键之间的传递依赖,确保了数据的一致性和规范性。它在设计数据库时更进一步地优化了关系模式的结构,消除了冗余和数据依赖的复杂性。
常用sql
-- 创建表
CREATE TABLE Customers (
CustomerID int PRIMARY KEY,
CustomerName varchar(255),
ContactName varchar(255),
Country varchar(255),
City varchar(255),
PostalCode varchar(255)
);
-- 插入数据
INSERT INTO Customers (CustomerID, CustomerName, ContactName, Country, City, PostalCode)
VALUES (1, 'Microsoft', 'John Doe', 'USA', 'Redmond', '98052');
-- 查询数据
SELECT * FROM Customers; -- 选择所有字段
SELECT CustomerName, Country FROM Customers; -- 选择特定字段
-- 更新数据
UPDATE Customers
SET ContactName = 'Jane Doe'
WHERE CustomerID = 1;
-- 删除数据
DELETE FROM Customers
WHERE CustomerID = 1;
-- 添加约束
ALTER TABLE Customers
ADD CONSTRAINT CHK_Customer_Positive_ID CHECK (CustomerID > 0);
-- 删除表
DROP TABLE Customers;
-- 创建索引
CREATE INDEX idx_Customers_City
ON Customers (City);
-- 删除索引
DROP INDEX idx_Customers_City ON Customers;
最后修改于 2023-07-15