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

DB2里头怎么弄那个验证约束,保证数据别乱填的那些事儿

这事儿说白了,就是你在DB2数据库里建表的时候,想给某些列立点规矩,不让用户随便瞎填,比如年龄不能填负数,性别只能是“男”或者“女”,邮箱地址得有个“@”符号,这个立规矩的功能,在DB2里头,主要就是靠“检查约束”来实现的,下面我就详细说说怎么弄。

最直接的办法:建表的时候就把规矩定好

大多数情况下,你在创建一张新表的时候,心里就已经清楚哪些字段不能乱来了,这时候,直接在 CREATE TABLE 语句里把约束加上去最省事儿。

比方说,我们要创建一张员工表,里面有员工编号、姓名、年龄和部门,我们想规定:年龄必须在18到65之间,部门只能是‘销售部’、‘技术部’或‘行政部’之一。

SQL语句可以这么写(根据DB2官方信息手册中关于CREATE TABLE语句的章节):

CREATE TABLE 员工表 (
    员工编号 INT NOT NULL PRIMARY KEY,
    姓名 VARCHAR(50) NOT NULL,
    年龄 INT CHECK (年龄 >= 18 AND 年龄 <= 65),
    部门 VARCHAR(20) CHECK (部门 IN ('销售部', '技术部', '行政部'))
);

你看,关键就在 CHECK 后面括号里的那个条件,这个条件就是个逻辑表达式,必须返回“真”数据才能被接受,如果你试图插入一条年龄为17岁或者部门是‘后勤部’的记录,DB2就会直接报错,拒绝执行,这样就保证了数据不会乱套。

表已经建好了,后来才想起来要立规矩怎么办?

很多时候,表可能早就存在了,里面已经有一些数据了,这时候你突然发现需要加个约束,总不能把表删了重建吧?当然不用,DB2提供了 ALTER TABLE 语句来修改已有的表(这个功能在DB2官方信息中心关于ALTER TABLE语句的章节有详细说明)。

还是用上面那个员工表的例子,假设表已经创建了,但当时忘了加年龄和部门的约束,现在想补上,可以这样做:

ALTER TABLE 员工表
ADD CONSTRAINT CHECK_年龄
CHECK (年龄 >= 18 AND 年龄 <= 65);
ALTER TABLE 员工表
ADD CONSTRAINT CHECK_部门
CHECK (部门 IN ('销售部', '技术部', '行政部'));

这里多了一个 CONSTRAINT CHECK_年龄 的东西,这是给这个约束起个名字,建表的时候可以省略名字,系统会自己生成一个很复杂的名字,但最好还是自己起个有意义的名字,CHECK_年龄,这样以后万一需要删除或者修改这个约束的时候,你都知道该找谁。

特别注意: 在给已有数据的表加约束时,DB2会先检查表里现有的数据是否都满足你这个新立的规矩,如果发现有一条数据不满足(比如已经有个员工年龄是17岁),那么整个添加约束的操作就会失败,你必须先把那些“不守规矩”的旧数据清理或者修改正确了,才能成功加上约束。

规矩可以更复杂一点

检查约束的条件不光是简单的比较和列举,它可以写得更复杂,满足更刁钻的需求。

举个例子,假设我们还有一个“用户表”,要求密码长度至少是8位,并且电子邮箱地址里必须包含“@”符号(根据DB2 SQL参考中关于谓词和条件表达式的章节,CHECK约束中可以使用多种函数和操作符)。

CREATE TABLE 用户表 (
    用户ID INT PRIMARY KEY,
    用户名 VARCHAR(30) NOT NULL,
    密码 VARCHAR(100) CHECK (LENGTH(密码) >= 8),
    邮箱 VARCHAR(100) CHECK (邮箱 LIKE '%@%')
);

这里用了 LENGTH 函数来检查密码的长度,用了 LIKE 操作符和通配符 来检查邮箱里是否有“@”,你甚至可以组合更多条件,比如用 ANDOR 来连接。

一些需要注意的坑

  1. NULL值的问题:这里有个很容易糊涂的地方,如果某个字段的值是NULL(空值),那么检查约束会怎么处理?答案是:大多数情况下,NULL值能通过检查,因为DB2的逻辑是,检查约束里的条件对于NULL值会评估为“未知”,而不是“假”,除非你的约束条件明确要求该字段不能为NULL(CHECK (年龄 IS NOT NULL AND 年龄 > 0)),否则光靠 CHECK (年龄 > 0) 是挡不住别人插入年龄为NULL的记录的,如果你坚决不允许NULL,最靠谱的做法是直接在字段后面加上 NOT NULL 约束,这和检查约束是两码事,但经常配合使用。

  2. 性能影响:每插入或更新一条数据,DB2都要去计算一下CHECK约束里的条件是否成立,如果条件写得太复杂,或者表的数据量巨大,多少会对性能有一点点影响,不过对于绝大多数常见的、简单的约束条件,这个开销微乎其微,完全不用担心,立规矩带来的数据准确性好处远大于这点性能开销。

  3. 别指望它做所有事:检查约束再好,它也只是在数据库层面进行非常“刻板”的数据校验,对于一些更复杂的业务逻辑,订单创建时间必须早于发货时间”这种需要跨列甚至跨表校验的情况,检查约束就有点力不从心了,那种复杂的业务规则,通常需要在应用程序代码里,或者通过数据库的“触发器”来实现。

在DB2里给数据立规矩,防止乱填,主要就是使用 CHECK 约束,可以在建表时一起创建,也可以后期用 ALTER TABLE 来添加,规矩的条件可以简单也可以比较复杂,用好了这个功能,你的数据库里的数据质量会大大提高,能避免很多因为手误或者理解错误导致的垃圾数据。

DB2里头怎么弄那个验证约束,保证数据别乱填的那些事儿