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 知识体系总览

下面这张图,是我自己总结的准确性校验知识体系。你可以把它当作一个检查清单,做项目时对照着来。

准确性校验知识体系 准确性校验 数值范围校验 格式校验 枚举值校验 正则表达式匹配 年龄 0-150 金额 > 0 库存 ≥ 0 日期格式 邮箱格式 手机号格式 性别 M/F/U 状态枚举 支付方式 身份证号 邮政编码 IP 地址 实践建议 1. 数值范围校验:结合业务上下文,不要用死边界 2. 格式校验:正则 + 函数双重验证,避免假阳性 3. 枚举值校验:注意大小写、空格、NULL 值处理 4. 正则匹配:复杂规则拆成多步,便于定位问题

4.6 实战中的组合拳

在实际项目中,我很少只用一种校验方法。往往是组合使用。

举个例子:校验一个「用户注册信息」表。

  1. 数值范围:年龄在 0-120 之间
  2. 格式校验:邮箱符合基本格式,手机号 11 位
  3. 枚举值:性别只能是 M/F/U
  4. 正则匹配:身份证号符合 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,业务方就多一次投诉。嗯,所以该查的查,该拦的拦,别手软。