当前位置:首页 > 问答 > 正文

带你慢慢摸索Sql Server里那些检查约束到底是咋回事,怎么用比较靠谱

说到数据库,尤其是 SQL Server,我们总希望存进去的数据是“干净”的,是符合我们业务规则的,人的年龄不能是负数,订单的金额必须大于0,性别的字段只能填“男”或“女”,你不能指望所有操作数据库的程序员都百分之百正确,也不能指望用户输入永远靠谱,这时候,就需要一个铁面无私的“守门员”,在数据踏进数据库大门的那一刻就进行检查,不合格的直接拦下,这个“守门员”,就是检查约束。

**检查约束到底是个啥?检查约束就像是你在表格的某个列上设置的一个“门卫”,所有想进去(插入)或者想修改的数据,都必须先过这个门卫的检查,只有符合你定下的规矩,数据才能被放行,否则就会被拒之门外,数据库会报错。

这个“规矩”,就是一个逻辑表达式,这个表达式的结果必须是“真”(True)或者“假”(False),对于一个“年龄”列,你可以设置检查约束为 Age >= 0,这样,如果有人试图插入一条年龄为 -5 的记录,这个表达式(-5 >= 0)的结果就是 False,数据库就会阻止这个操作。

检查约束怎么创建?

根据微软官方文档(来源:Microsoft Learn - CREATE TABLE (Transact-SQL) 和 ALTER TABLE (Transact-SQL)),创建检查约束主要有两种方式,一种是在创建表的时候一起定义,另一种是表已经存在了,再去给它添加约束。

  1. 建表时创建: 这就像盖房子的时候直接把规矩定好,你可以在定义每个列的时候顺手写上约束,也可以在最后统一写,举个简单的例子,我们创建一个“学生表”:

    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 这样的乱码名字,你根本记不住。

  2. 表已存在,后期添加: 如果表已经创建好了,但发现忘了加约束,或者业务规则后来发生了变化,你可以使用 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位。

使用检查约束的“靠谱”建议

  1. 起个有意义的名字: 前面已经强调过了,这绝对是重中之重。CK_表名_列名_规则简述 是个不错的命名习惯,这在你需要排查数据问题或者修改约束时,能帮你省下大量时间。
  2. 保持简单和高效: 检查约束是在每次插入或更新数据时执行的,虽然功能强大,但不要在里面写过于复杂的逻辑或者调用自定义函数,这可能会影响数据库的性能,非常复杂的业务逻辑最好放在应用程序层或者通过触发器来实现。
  3. 理解 NULL 值的影响: 这一点非常关键!检查约束只在表达式计算结果为 FALSE 时才会拒绝数据,如果表达式的结果是 UNKNOWN(当参与计算的列包含 NULL 值时),约束是不会触发的,你有一个约束 Salary > 1000,如果你插入一条 Salary 为 NULL 的记录,NULL > 1000 的结果是 UNKNOWN,不是 FALSE,所以这条记录会被允许插入,如果你不希望该列为空,应该同时设置该列为 NOT NULL
  4. 谨慎处理跨列约束: 检查约束可以引用同一行内的其他列,在一个“订单明细”表里,你可以设置 CHECK (UnitPrice * Quantity = LineTotal),确保行的总价等于单价乘以数量,这很强大,但要小心,因为如果计算逻辑非常复杂,可能会带来维护上的困难。
  5. 禁用约束的特殊情况: 在某些场景下,比如需要一次性导入大量历史数据,而其中部分数据可能不满足当前的约束规则,你可以临时禁用约束,导入完成后再启用它,并同时检查现有数据是否合规,使用 ALTER TABLE ... NOCHECK CONSTRAINT ... 来禁用,用 ALTER TABLE ... CHECK CONSTRAINT ... 来重新启用,但这是个危险操作,务必谨慎使用。

检查约束是 SQL Server 中一个非常实用且强大的数据完整性工具,它就像是你数据库的“基层保安”,用清晰、明确的规则从最底层保证垃圾数据不会轻易入库,花点时间为你表里重要的业务规则设置好检查约束,能为你后续的数据维护工作避免无数的麻烦,先从简单的规则开始用起,慢慢摸索,你就会发现它不可或缺。

带你慢慢摸索Sql Server里那些检查约束到底是咋回事,怎么用比较靠谱