做了这么多年数据库开发,我越来越觉得SQL里的REGEXP正则表达式是个被低估的技能。平时大家写查询,用到最多的就是LIKE加几个百分号,但真遇到“手机号格式是否合法”“这个字段里有没有连续重复的标点”“能不能从日志串里把IP和状态码抠出来”这类需求,LIKE那套模糊匹配根本不够用。REGEXP就是专门解决这类“结构未知但模式可描述”的匹配问题的,它能让一条SQL干完原本要写好几层CASE WHEN或者拉出去用脚本处理的活。这篇文章我把REGEXP在SQL里的使用从语法、数据库差异到实战场景都过一遍,适合正在搞数据清洗、接口校验、报表开发和慢SQL优化的人参考,不管你是MySQL、PostgreSQL还是Oracle用户,都能找到能直接抄的方案。
1. 为什么SQL查询需要正则表达式
1.1 从LIKE的痛点说起
LIKE的优点是简单,缺点就是匹配能力太粗。百分号和下划线两个通配符,只能表达“任意一串字符”和“任意单个字符”,根本没法表达“至少一个数字”“连续4到8个小写字母”“以1开头且第二位是3到9”这种规则。实际开发中,做手机号校验时经常看到有人写 phone LIKE '1%',结果一堆“10086客服”“1号店会员”之类根本不是手机号的数据也匹配进去了。原因很简单,LIKE只看前后缀,没法约束每一位到底是什么字符。正则就不一样,^1[3-9][0-9]{9}$ 表达得非常精确:1开头、第二位3到9、后面9位数字,一共11位。这种精度是LIKE做不到的。
还有一点,LIKE在匹配“内容包含某类字符但位置不固定”的情况时特别痛苦。比如要从备注字段里找“包含金额”的记录,金额可能是1.5、20、300.25,你不可能用LIKE把每种情况都写出来,但正则 [0-9]+(\\.[0-9]{1,2})? 一条就搞定。LIKE擅长的是“前后缀明确的模糊查询”,一旦规则复杂一点,SQL就会写得又臭又长,性能还不一定好。
1.2 REGEXP的真正用武之地
正则表达式在SQL里的价值,主要体现在几个场景。第一是数据清洗,从脏数据里识别格式异常的记录,比如身份证号位数不对、邮箱少了@、金额字段混入了字母,这种规则用LIKE表达非常费劲,用正则几秒钟就能写出来。第二是日志分析,从一段混合文本中提取IP、时间、状态码、SQL语句片段,这算是REGEXP_SUBSTR的看家本领。第三是接口和入库校验,在INSERT之前用正则做白名单校验,防止非法格式进入库,这个在数据仓库和接口对接中很常见。第四是ETL流程中的标准化,把各种写法的手机号、电话、日期统一成标准格式,用REGEXP_REPLACE一步搞定。
概括一下,凡是“规则可以用模式描述、但值本身千变万化”的校验和提取需求,都是正则的主场。数据量越大,字段内容越杂乱,正则带来的收益越明显。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 各数据库的正则能力差异
2.1 MySQL:从REGEXP到完整的正则函数族
MySQL是最早把REGEXP当成常用操作符的数据库之一。老版本里只有 REGEXP / RLIKE,作用是返回0或1,配合WHERE使用,比如 SELECT * FROM user WHERE name REGEXP '^张'。注意MySQL的REGEXP是“部分匹配”语义,只要字符串某个位置能匹配上就返回真,不像LIKE那样多数情况下在要求全串匹配。所以做格式校验时,必须自己加头部锚点 ^ 和尾部锚点 $,这个细节很多人第一次用都踩过。
MySQL 8.0补齐了 REGEXP_LIKE、REGEXP_REPLACE、REGEXP_SUBSTR、REGEXP_INSTR 一套完整函数,做提取和替换就方便多了。REGEXP_LIKE本质上和REGEXP一样,只是函数风格更接近Oracle。REGEXP_SUBSTR可以从字符串里直接截取匹配片段,REGEXP_REPLACE可以做替换,REGEXP_INSTR返回匹配位置。MySQL 8.0还有个变化,正则引擎从Henry Spencer换成了ICU,默认行为也变了。5.7时代REGEXP默认不区分大小写(受排序规则影响),8.0起默认区分大小写,需要忽略大小写时得指定 'i' 参数。比如 REGEXP_REPLACE(name, 'abc', 'x', 'i') 里的第四个参数,就是8.0新增的匹配参数。
2.2 PostgreSQL:POSIX风格正则
PostgreSQL的正则支持在开源数据库里算是最完整的,走的是POSIX风格。操作符有四个:~、~*、!~、!~*,分别对应“匹配”“不区分大小写匹配”“不匹配”“不区分大小写不匹配”,用起来比函数简洁很多。同时PostgreSQL还提供了 REGEXP_MATCHES、REGEXP_REPLACE、REGEXP_SPLIT_TO_ARRAY、REGEXP_SPLIT_TO_TABLE 等函数,能在各种场景下切片、提取、拆分。
另外PostgreSQL还有个 SIMILAR TO 操作符,介于LIKE和正则之间,兼容SQL标准。但实际工作中用的人不多,因为它的语法既不像LIKE那么直观,又没有POSIX正则的表达能力强。我建议直接学 ~ 操作符和 REGEXP_ 系列函数,没必要为了“标准”去学SIMILAR TO,很多情况下SIMILAR TO写完还得到处查文档。
