带你慢慢摸索Sql Server里那些检查约束到底是咋回事,怎么用比较靠谱
- 问答
- 2026-01-11 09:31:48
- 1
说到数据库,尤其是 SQL Server,我们总希望存进去的数据是“干净”的,是符合我们业务规则的,人的年龄不能是负数,订单的金额必须大于0,性别的字段只能填“男”或“女”,你不能指望所有操作数据库的程序员都百分之百正确,也不能指望用户输入永远靠谱,这时候,就需要一个铁面无私的“守门员”,在数据踏进数据库大门的那一刻就进行检查,不合格的直接拦下,这个“守门员”,就是检查约束。
**检查约束到底是个啥?检查约束就像是你在表格的某个列上设置的一个“门卫”,所有想进去(插入)或者想修改的数据,都必须先过这个门卫的检查,只有符合你定下的规矩,数据才能被放行,否则就会被拒之门外,数据库会报错。
这个“规矩”,就是一个逻辑表达式,这个表达式的结果必须是“真”(True)或者“假”(False),对于一个“年龄”列,你可以设置检查约束为 Age >= 0,这样,如果有人试图插入一条年龄为 -5 的记录,这个表达式(-5 >= 0)的结果就是 False,数据库就会阻止这个操作。
检查约束怎么创建?
根据微软官方文档(来源:Microsoft Learn - CREATE TABLE (Transact-SQL) 和 ALTER TABLE (Transact-SQL)),创建检查约束主要有两种方式,一种是在创建表的时候一起定义,另一种是表已经存在了,再去给它添加约束。
-
建表时创建: 这就像盖房子的时候直接把规矩定好,你可以在定义每个列的时候顺手写上约束,也可以在最后统一写,举个简单的例子,我们创建一个“学生表”:
CREATE TABLE Students ( StudentID int PRIMARY KEY, StudentName nvarchar(50) NOT NULL, Age int CHECK (Age >= 0 AND Age <= 120), -- 方式一:直接在列定义后面写 Gender nchar(1) CHECK (Gender IN ('男', '女')), Score decimal(5,2), -- 方式二:在表定义的末尾统一写约束,这样可以给约束起个名字 CONSTRAINT CK_Student_Score CHECK (Score >= 0 AND Score <= 100) );你看,对于 Age 和 Gender 列,我们用了第一种方式,简单直接,但对于 Score(分数)列,我们用了第二种方式,并且用
CONSTRAINT关键字给这个约束起了个名字叫CK_Student_Score。强烈建议你养成给约束起名字的习惯,因为以后万一需要修改或删除这个约束,有个名字会方便得多,不然数据库会自己生成一个类似CK__Students__Score__12345678这样的乱码名字,你根本记不住。 -
表已存在,后期添加: 如果表已经创建好了,但发现忘了加约束,或者业务规则后来发生了变化,你可以使用
ALTER TABLE语句来添加,我们发现“学生表”里缺了个“邮箱格式”的约束,可以这样加:ALTER TABLE Students ADD CONSTRAINT CK_Student_EmailFormat CHECK (Email LIKE '%_@%_.__%');
这个约束使用了
LIKE操作符和通配符,是一个非常基础的邮箱格式检查,确保邮箱地址里至少有一个符号,并且后面还有点,实际应用中可能需要更复杂的正则表达式(但 T-SQL 的原生支持有限)。
检查约束里都能写些啥?
检查约束的表达能力很强,你可以使用很多运算符和函数来构建你的业务规则(来源:Microsoft Learn - CHECK Constraints)。
- 比较运算符: (等于),
>(大于),<(小于),>=,<=,<>(不等于)。Price > 0。 - 逻辑运算符:
AND(与),OR(或),NOT(非)。(Age >= 18 AND Age <= 65)。 - 范围检查: 可以用
BETWEEN ... AND ...,Score BETWEEN 0 AND 100,这和Score >= 0 AND Score <= 100是等价的。 - 集合检查: 可以用
IN (...),Status IN ('待支付', '已支付', '已发货', '已完成'),确保值只能是这几个选项之一。 - 模式匹配: 用
LIKE和通配符,就像上面检查邮箱的例子。 - 使用函数: 你可以调用一些内置函数。
CHECK (LEN(ProductCode) = 10)确保产品代码长度是10位。
使用检查约束的“靠谱”建议
- 起个有意义的名字: 前面已经强调过了,这绝对是重中之重。
CK_表名_列名_规则简述是个不错的命名习惯,这在你需要排查数据问题或者修改约束时,能帮你省下大量时间。 - 保持简单和高效: 检查约束是在每次插入或更新数据时执行的,虽然功能强大,但不要在里面写过于复杂的逻辑或者调用自定义函数,这可能会影响数据库的性能,非常复杂的业务逻辑最好放在应用程序层或者通过触发器来实现。
- 理解 NULL 值的影响: 这一点非常关键!检查约束只在表达式计算结果为 FALSE 时才会拒绝数据,如果表达式的结果是 UNKNOWN(当参与计算的列包含 NULL 值时),约束是不会触发的,你有一个约束
Salary > 1000,如果你插入一条 Salary 为 NULL 的记录,NULL > 1000的结果是 UNKNOWN,不是 FALSE,所以这条记录会被允许插入,如果你不希望该列为空,应该同时设置该列为NOT NULL。 - 谨慎处理跨列约束: 检查约束可以引用同一行内的其他列,在一个“订单明细”表里,你可以设置
CHECK (UnitPrice * Quantity = LineTotal),确保行的总价等于单价乘以数量,这很强大,但要小心,因为如果计算逻辑非常复杂,可能会带来维护上的困难。 - 禁用约束的特殊情况: 在某些场景下,比如需要一次性导入大量历史数据,而其中部分数据可能不满足当前的约束规则,你可以临时禁用约束,导入完成后再启用它,并同时检查现有数据是否合规,使用
ALTER TABLE ... NOCHECK CONSTRAINT ...来禁用,用ALTER TABLE ... CHECK CONSTRAINT ...来重新启用,但这是个危险操作,务必谨慎使用。
检查约束是 SQL Server 中一个非常实用且强大的数据完整性工具,它就像是你数据库的“基层保安”,用清晰、明确的规则从最底层保证垃圾数据不会轻易入库,花点时间为你表里重要的业务规则设置好检查约束,能为你后续的数据维护工作避免无数的麻烦,先从简单的规则开始用起,慢慢摸索,你就会发现它不可或缺。

本文由颜泰平于2026-01-11发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/78611.html
