4. 准确性校验:数值范围、格式、枚举值与正则匹配
准确性校验,说白了就是检查数据是不是「对」的。不是格式对,而是真实世界里的那个值对不对。
我刚开始做数据治理时,接过一个客户案例。他们的订单金额字段里,居然有一条记录是 -999999。你说这数据格式没问题吧?数值字段,负号加数字,完全合法。但你说它准确吗?显然不。这就是准确性校验要解决的问题。
核心观点:准确性校验 ≠ 格式校验。格式对不代表数据对。准确性关注的是「值是否在合理范围内」「是否符合业务预期」「是否匹配真实情况」。
4.1 数值范围校验
数值范围校验,是准确性校验里最基础、也最常用的一类。我几乎在每个项目里都会用到它。
什么时候需要做?
- 年龄字段:0-150(别笑,我真见过录入成 999 的)
- 订单金额:大于 0,小于某个上限
- 库存数量:不能为负数
- 评分字段:1-5 星
写规则时,我习惯用 下界 + 上界 的方式定义。不要只写一个边界,那样容易漏掉异常值。
-- SQL 示例:校验订单金额是否在合理范围
SELECT order_id, amount
FROM orders
WHERE amount <= 0
OR amount > 1000000;
-- 这条 SQL 会找出金额异常的所有订单
我的小技巧:数值范围校验最好结合业务上下文。比如「学生成绩」字段,不同年级的满分可能不同。我曾经踩过这个坑——统一用 100 分校验,结果漏掉了某次满分 150 的考试数据。
4.2 格式校验
格式校验,检查的是数据「长得好不好看」。嗯,说白了就是符不符合我们约定的模板。
4.2.1 日期格式校验
日期格式的坑,我数都数不过来。YYYY-MM-DD、YYYY/MM/DD、DD-MM-YYYY、甚至还有中文的「2024年1月1日」……你想想看,如果系统里混了三种格式,下游程序不报错才怪。
-- 校验日期格式是否为 YYYY-MM-DD
SELECT date_field
FROM my_table
WHERE date_field NOT REGEXP '^[0-9]{4}-[0-9]{2}-[0-9]{2}$';
-- 注意:这只是格式校验,不校验日期是否合法(比如 2024-02-30 就过不了)
注意:正则只能校验「长相」,不能校验「合理性」。比如 2024-02-30 这个日期,正则能通过,但实际不存在。我建议格式校验之后,再加一层日期函数转换校验,双重保险。
4.2.2 邮箱格式校验
邮箱校验,看起来简单,其实挺烦人。RFC 5322 标准下的邮箱格式极其复杂。但在实际项目中,我们不需要那么严格。
我个人习惯用这个规则:
- 必须包含 @ 符号
- @ 前后不能为空
- 域名部分至少有一个点
- 不能有空格
-- 简单邮箱格式校验
SELECT email
FROM users
WHERE email NOT REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$';
避坑指南:我曾经遇到过邮箱里带加号的情况(比如 user+tag@example.com),这是合法的。很多简单的正则会把这种判为非法,要注意。
4.2.3 手机号格式校验
手机号校验,不同国家规则不同。国内的话,11 位数字,1 开头,第二位通常是 3/5/7/8/9。
-- 中国大陆手机号校验
SELECT phone
FROM contacts
WHERE phone NOT REGEXP '^1[3-9][0-9]{9}$';
但要注意,这只是格式校验。号码是否真的在用、是否属于某个运营商,那是另一回事。
4.3 枚举值校验
枚举值校验,检查字段值是否在预定义的集合里。说白了,就是「只能从这几个里面选」。
举个例子:性别字段,业务上只允许 'M'、'F'、'U'(未知)。如果出现 'Male' 或 '女',那就是问题。
-- 枚举值校验示例
SELECT gender, COUNT(*) as cnt
FROM employees
WHERE gender NOT IN ('M', 'F', 'U')
GROUP BY gender;
-- 这条 SQL 会列出所有不在枚举范围内的值
| 字段 | 允许的枚举值 | 常见异常值 |
|---|---|---|
| gender | M, F, U | Male, Female, 男, 女, NULL |
| status | active, inactive, suspended | Active, 激活, 1, 0 |
| payment_method | credit_card, debit_card, wechat, alipay | 信用卡, 支付, cash |
注意大小写和空格:枚举值校验最容易被忽略的就是大小写和前后空格。'Active' 和 'active' 在计算机眼里是两个不同的值。我建议在校验前先做一次 trim 和 lower 处理。
4.4 正则表达式匹配
正则表达式,是准确性校验的瑞士军刀。它能处理前面三种方法搞不定的复杂场景。
什么时候用正则?
- 身份证号校验(18 位,最后一位可能是 X)
- 邮政编码校验(6 位数字)
- IP 地址格式校验
- 自定义编码规则(比如产品编号:字母+数字+特定格式)
-- 身份证号简单格式校验(18 位,数字或 X 结尾)
SELECT id_card
FROM citizens
WHERE id_card NOT REGEXP '^[1-9][0-9]{5}(19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$';
-- 这个正则已经包含了出生日期的基本校验
我的经验:正则表达式不是越复杂越好。太长的正则难以维护,也容易出错。我习惯把复杂的校验拆成多个简单步骤。比如先校验长度,再校验格式,最后校验校验位。每一步出问题都能单独定位。
4.5 知识体系总览
下面这张图,是我自己总结的准确性校验知识体系。你可以把它当作一个检查清单,做项目时对照着来。
4.6 实战中的组合拳
在实际项目中,我很少只用一种校验方法。往往是组合使用。
举个例子:校验一个「用户注册信息」表。
- 数值范围:年龄在 0-120 之间
- 格式校验:邮箱符合基本格式,手机号 11 位
- 枚举值:性别只能是 M/F/U
- 正则匹配:身份证号符合 18 位规则
-- 组合校验示例
SELECT user_id,
CASE
WHEN age < 0 OR age > 120 THEN '年龄异常'
WHEN email NOT REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' THEN '邮箱格式异常'
WHEN phone NOT REGEXP '^1[3-9][0-9]{9}$' THEN '手机号格式异常'
WHEN gender NOT IN ('M', 'F', 'U') THEN '性别枚举异常'
WHEN id_card NOT REGEXP '^[1-9][0-9]{5}(19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$' THEN '身份证格式异常'
ELSE '正常'
END as check_result
FROM user_registration
WHERE age < 0 OR age > 120
OR email NOT REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
OR phone NOT REGEXP '^1[3-9][0-9]{9}$'
OR gender NOT IN ('M', 'F', 'U')
OR id_card NOT REGEXP '^[1-9][0-9]{5}(19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$';
我的习惯:写校验规则时,我会先跑一遍「正常数据」,确保规则不会误杀。然后再跑「异常数据」,看看能不能抓到问题。两边都过了,才敢上线。这个习惯帮我避免过好几次线上事故。
准确性校验,说到底就是「较真」。数据治理这行,不较真不行。你放过去一条异常数据,下游可能就多一个 Bug,业务方就多一次投诉。嗯,所以该查的查,该拦的拦,别手软。