如何在 SQL Server 中创建 CHECK 约束(T-SQL 示例)

发布于

在 SQL Server 中,可以在表中创建 CHECK 约束,以指定在一列或多列中可接受的数据值。

如果表具有约束,并且您尝试提供不符合约束的数据,则操作将失败并显示错误。CHECK``CHECK

这有助于维护数据完整性,因为它有助于防止无效数据进入数据库。

创建约束时,需要提供返回 或 的逻辑表达式。此逻辑表达式用于检查数据。CHECK``TRUE``FALSE

CHECK约束类似于外键约束,因为它们控制放在列中的值。但是,区别在于它们如何确定哪些值是有效的:外键约束从另一个表中获取有效值的列表,而约束从逻辑表达式中确定有效值。CHECK

可以在列级别或表级别定义约束。列级约束仅适用于该列中的数据。表级约束应用于整行,并检查来自多列的数据。

下面是创建列级和表级约束的示例。CHECK

示例 1 – 创建列级 CHECK 约束

下面是在创建表时创建基本列级约束的示例。CHECK

CREATE TABLE ConstraintTest ( ConstraintTestId int IDENTITY(1,1) NOT NULL PRIMARY KEY, Price smallmoney NOT NULL, CONSTRAINT chkPrice CHECK (Price > 0) );

在这个示例中,约束指定列中的所有数据必须大于 0。换句话说,价格不能为零,也不能为负数。这是一个列级约束,因为它适用于一列中的数据。CHECK``Price

因为这是一个列级约束,所以我可以将其定义为列的一部分(不带逗号)。所以我本可以这样做:

CREATE TABLE ConstraintTest ( ConstraintTestId int IDENTITY(1,1) NOT NULL PRIMARY KEY, Price smallmoney NOT NULL CONSTRAINT chkPrice CHECK (Price > 0) );

无论哪种方式,让我们尝试插入一个无效值:

INSERT INTO ConstraintTest ( Price ) VALUES ( 0 );

输出:

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "chkPrice". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'Price'.

示例 2 – 添加更多列和另一个列级 CHECK 约束

让我们向表中添加更多列,然后添加另一个列级约束。CHECK

ALTER TABLE ConstraintTest ADD TeamSize tinyint NOT NULL, StartDate date NOT NULL, EndDate date NOT NULL, CONSTRAINT chkTeamSize CHECK (TeamSize >= 3 AND TeamSize <= 15) ;

其中一个新列记录团队成员的数量。在这种情况下,业务规则是团队必须至少有 3 个成员,但不超过 15 个。因此,数据库应防止团队成员少于 3 人或超过 15 人的情况。

让我们尝试插入一个无效值:

INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 2, ‘2020-01-01’, ‘1900-02-02’ );

输出:

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.

示例 3 – 添加表级 CHECK 约束

现在,让我们添加一个表级约束。这将检查两列中的数据。

顺便说一下,您不必添加另一列即可添加约束。您可以简单地单独添加约束。CHECK

例:

ALTER TABLE ConstraintTest ADD CONSTRAINT chkValidEndDate CHECK (EndDate >= StartDate) ;

在这个示例中,我添加一个约束以确保结束日期永远不会早于开始日期。这是跨两列检查数据,因此是表级约束。

尝试插入无效值:

INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 3, ‘2020-01-01’, ‘1900-02-02’ );

输出:

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "chkValidEndDate". The conflict occurred in database "Test", table "dbo.ConstraintTest".

请注意,为了测试此约束,我必须将团队成员增加到 3,以防止首先触发前一个约束(约束按创建顺序进行验证)。CHECK

示例 4 – 更改检查约束

您实际上无法更改约束。如果需要更改它,则需要删除它并使用新定义创建它。CHECK

例:

ALTER TABLE ConstraintTest DROP CONSTRAINT chkTeamSize;

ALTER TABLE ConstraintTest ADD CONSTRAINT chkTeamSize CHECK (TeamSize >= 5 AND TeamSize <= 20) ;

如前所述,约束按创建顺序进行验证,因此这可能会影响首先捕获哪个错误。CHECK

因此,在这种情况下,如果我尝试插入无效值(并且还包括无效日期),则无效日期将首先被捕获:

INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 4, ‘2020-01-01’, ‘1900-02-02’ );

输出:

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "chkValidEndDate". The conflict occurred in database "Test", table "dbo.ConstraintTest".

因此,为了检查我的最新约束,我需要先解决日期问题:

INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 4, ‘2020-01-01’, ‘2020-02-02’ );

输出:

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.

所以我的最新约束是按预期工作。

示例 5 – 检查约束和标识列

因此,现在我们已经测试了约束,让我们继续插入有效数据:

INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 5, ‘2020-01-01’, ‘2020-02-02’ );

输出:

+--------------------+---------+------------+-------------+------------+
| ConstraintTestId   | Price   | TeamSize   | StartDate   | EndDate    |
|--------------------+---------+------------+-------------+------------|
| 13                 | 1.0000  | 5          | 2020-01-01  | 2020-02-02 |
+--------------------+---------+------------+-------------+------------+

最后,我们得到了一个成功的插入。

但是,您会注意到该列已增加到 13。IDENTITY

记得当我第一次创建表时,我定义了要使用的列,这意味着它应该从 1 开始,并在每插入一行时自动递增 1。ConstraintTestId``IDENTITY(1,1)

但是现在我终于插入了第一行,值已经是 13。这是因为即使约束导致操作失败,列也会递增。IDENTITY``CHECK``INSERT

请注意,在为本文提供示例时,我进行了一些额外的失败插入,因此该值已增加到比您只是按照本文逐步操作时将获得的值更高的值。

无论如何,让我们进行最后一次失败的插入,然后进行成功的插入以确认这一点。

插入失败:

INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 2, 4, ‘2020-01-02’, ‘2020-02-03’ );

输出:

Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.

成功插入:

INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 2, 6, ‘2020-01-02’, ‘2020-02-03’ );

SELECT * FROM ConstraintTest;

输出:

+--------------------+---------+------------+-------------+------------+
| ConstraintTestId   | Price   | TeamSize   | StartDate   | EndDate    |
|--------------------+---------+------------+-------------+------------|
| 13                 | 1.0000  | 5          | 2020-01-01  | 2020-02-02 |
| 15                 | 2.0000  | 6          | 2020-01-02  | 2020-02-03 |
+--------------------+---------+------------+-------------+------------+

我们可以看到列从 13 跳到 15,因此在插入失败期间它明显增加。IDENTITY

检查约束的一些限制

以下是使用约束时需要注意的一些限制:CHECK

  • 搜索条件的计算结果必须为布尔表达式,并且不能引用另一个表。
  • 表达式不能包含别名数据类型。
  • CHECK不能对文本、ntext 或图像列定义约束。