前些天发现了一个人工智能学习网站,通俗易懂,风趣幽默,最重要的屌图甚多,忍不住分享一下给大家。点击跳转到网站。
概念性——了解 SQL 约束
介绍
在设计数据库时,有时我们可能希望对某些列中允许的数据进行限制。例如,如果我们要创建一个保存摩天大楼信息的表,我们可能希望保存每栋建筑物高度的列禁止出现负值。
关系数据库管理系统 (RDBMS) 允许我们控制将哪些数据添加到带有约束的表中。约束是一种特殊规则,适用于一个或多个列(或整个表),它限制可以对表数据进行的更改(无论是通过 INSERT
或UPDATE
、DELETE
)。
本文将详细回顾什么是约束以及它们在 RDBMS 中的使用方式。它还将逐步介绍 SQL 标准中定义的五个约束,并解释它们各自的功能。
什么是约束?
在 SQL 中,约束是应用于列或表的任何规则,用于限制可以输入的数据。每当我们尝试执行更改表中保存的数据的操作(例如INSERT
、UPDATE
或DELETE
语句)时,RDBMS 都会测试该数据是否违反任何现有约束,如果是,则返回错误。
数据库管理员通常依靠约束来确保数据库遵循一组定义的业务规则。在数据库的上下文中,业务规则是企业或其他组织遵循的任何策略或过程,并且其数据也必须遵守。例如,假设我们正在构建一个数据库来对客户的商店库存进行编目。如果客户指定每个产品记录应具有唯一的标识号,我们可以创建一个带有UNIQUE
约束的列,以确保该列中没有两个条目相同。
约束也有助于维护数据完整性。数据完整性是一个广义术语,通常用于根据特定用例描述数据库中保存的数据的整体准确性、一致性和合理性。数据库中的表通常密切相关,一个表中的列依赖于另一个表中的值。由于数据输入通常容易出现人为错误,因此约束在这种情况下很有用,因为它们可以帮助确保错误输入的数据不会影响此类关系,从而损害数据库的数据完整性。
想象一下,我们正在设计一个包含两个表的数据库:一个用于列出学校当前的学生,另一个用于列出该学校篮球队的成员。我们可以FOREIGN KEY
对篮球队表中引用学校表中的列的列应用约束。这将通过要求团队表中的任何条目引用学生表中的现有条目来建立两个表之间的关系。
用户在首次创建表时定义约束,或者稍后使用语句添加约束,ALTER TABLE
只要它不与表中已有的任何数据冲突即可。当我们创建约束时,数据库系统将自动为其生成一个名称,但在大多数 SQL 实现中,我们可以为任何约束添加自定义名称。这些名称用于ALTER TABLE
在更改或删除语句时引用语句中的约束。
SQL 标准正式定义了五个约束:
PRIMARY KEY
FOREIGN KEY
UNIQUE
CHECK
NOT NULL
注意:许多 RDBMS 都包含DEFAULT
关键字,该关键字用于定义列的默认值,除非NULL
在插入行时未指定值。其中一些数据库管理系统的文档称为DEFAULT
约束,因为它们的 SQL 实现使用DEFAULT
类似于UNIQUE
或 等约束的语法CHECK
。但是,DEFAULT
从技术上讲,这不是一个约束,因为它不限制可以在列中输入哪些数据。
现在我们已经大致了解了如何使用约束,让我们仔细看看这五个约束中的每一个。
PRIMARY KEY
该
PRIMARY KEY
约束要求给定列中的每个条目既唯一又不唯一NULL
,并允许我们使用该列来标识表中的每个单独行
在关系模型中,键是表中的一列或一组列,其中每个值都保证是唯一的并且不包含任何NULL
值。主键是一种特殊的键,其值用于标识表中的各个行,构成主键的列可用于在数据库的其余部分中标识该表。
这是关系数据库的一个重要方面:使用主键,用户不需要知道他们的数据在计算机上的物理存储位置,他们的 DBMS 可以跟踪每条记录并临时返回它们。反过来,这意味着记录没有定义的逻辑顺序,用户可以按任何顺序或通过他们希望的任何过滤器返回数据。
我们可以在 SQL 中使用约束创建主键,该约束本质上是和约束PRIMARY KEY
的组合。定义主键后,DBMS 将自动创建与其关联的*索引。*索引是一种数据库结构,有助于更快地从表中检索数据。与教科书中的索引类似,查询只需检查索引列中的条目即可找到关联的值。这使得主键可以充当表中每一行的标识符。
一张表只能有一个主键,但与常规键一样,主键可以包含多个列。话虽如此,主键的一个定义特征是它们仅使用唯一标识表中每一行所需的最小属性集。为了说明这个想法,想象一个使用以下三列存储有关学校学生信息的表:
studentID
:用于保存每个学生唯一的身份证号码firstName
:用于保存每个学生的名字lastName
:用于保存每个学生的姓氏
学校里的一些学生可能会共用一个名字,从而使该firstName
列成为一个会重复的主键选择。对于其它列来说也是如此。
FOREIGN KEY
该
FOREIGN KEY
约束要求给定列中的每个条目必须已存在于另一个表的特定列中。
如果我们有两个表想要相互关联,一种方法是使用约束定义外键FOREIGN KEY
。外键是一个表(“子”表)中的一列,其值来自另一个表(“父”)中的键。这是表达两个表之间关系的一种方式:FOREIGN KEY
约束要求它所应用的列中的值必须已经存在于它引用的列中。
下图突出显示了两个表之间的这种关系:一个用于记录公司员工的信息,另一个用于跟踪公司的销售情况。在此示例中,表的主键EMPLOYEES
由表的外键引用SALES
:
如果我们尝试向子表添加记录,并且在外键列中输入的值在父表的主键中不存在,则插入语句将无效。这有助于维护关系级完整性,因为两个表中的行始终正确关联。
通常,表的外键是父表的主键,但情况并非总是如此。在大多数 RDBMS 中,父表中应用了UNIQUE
或PRIMARY KEY
约束的任何列都可以由子表的外键引用。
UNIQUE
该
UNIQUE
约束禁止将任何重复值添加到给定列。
顾名思义,UNIQUE
约束要求给定列中的每个条目都是唯一值。任何尝试添加已出现在列中的值都将导致错误。
UNIQUE
约束对于强制表之间的一对一关系很有用。如前所述,我们可以使用外键在两个表之间建立关系,但表之间可以存在多种关系:
- 一对一:如果父表中的行与子表中的一行且仅一行相关,则称两个表具有一对一关系
- 一对多:在多对多关系中,父表中的一行可以与子表中的多行相关,但子表中的每一行只能与父表中的一行相关
- 多对多:如果父表中的行可以与子表中的多行相关,反之亦然,则称两者具有多对多关系
UNIQUE
通过向已应用约束的列添加约束FOREIGN KEY
,可以确保父表中的每个条目在子表中只出现一次,从而在两个表之间建立一对一的关系。
UNIQUE
请注意,我们可以在表级别和列级别定义约束。当在表级别定义时,UNIQUE
约束可以应用于多个列。在这种情况下,约束中包含的每一列都可以有重复的值,但每一行必须在受约束的列中具有唯一的值组合。
CHECK
约束
CHECK
定义了对列的要求(称为谓词),其中输入的每个值都必须满足该要求。
CHECK
约束谓词以表达式的形式编写,可以计算为TRUE
、FALSE
或潜在的UNKNOWN
。如果我们尝试在具有约束的列中输入一个值CHECK
,并且该值导致谓词计算为TRUE
or UNKNOWN
(对于NULL
值会发生这种情况),则操作将会成功。但是,如果表达式解析为FALSE
,它将失败。
CHECK
谓词通常依赖于数学比较运算符(例如<
, >
, <=
, OR >=
)来限制允许进入给定列的数据范围。例如,CHECK
约束的一种常见用途是在负值没有意义的情况下防止某些列保留负值,如下例所示。
该CREATE TABLE
语句创建一个表,该表productInfo
以每个产品的名称、标识号和价格的列命名。由于产品的价格为负数是没有意义的,因此此语句对该列施加了约束,CHECK
以price
确保它仅包含正值:
CREATE TABLE productInfo (
productID int,
name varchar(30),
price decimal(4,2)
CHECK (price > 0)
);
并非每个CHECK
谓词都必须使用数学比较运算符。通常,我们可以在谓词中使用任何可计算为TRUE
、FALSE
、 或 的SQL 运算符,包括UNKNOWN
、CHECK
、LIKE
、BETWEEN
等。某些 SQL 实现(但不是全部)甚至允许我们在谓词中包含子查询。但请注意,大多数实现不允许我们在谓词中引用另一个表。
NOT NULL
该
NOT NULL
约束禁止将任何NULL
值添加到给定列。
在大多数 SQL 实现中,如果添加一行数据但没有为特定列指定值,数据库系统将默认将缺失的数据表示为NULL
。在 SQL 中,NULL
是一个特殊关键字,用于表示未知、缺失或未指定的值。然而,NULL
它本身并不是一个值,而是一个未知值的状态。
顾名思义,该NOT NULL
约束防止给定列中的任何值成为NULL
。这意味着对于任何具有NOT NULL
约束的列,在插入新行时必须为其指定一个值。否则,INSERT
操作将会失败。
结论
对于任何想要设计具有高水平数据完整性和安全性的数据库的人来说,约束都是必不可少的工具。通过限制输入列中的数据,我们可以确保正确维护表之间的关系,并且数据库遵守定义其用途的业务规则。