SQL 正则表达式高级使用实战

1次阅读

mysql 8.0+ 使用 regexp_like 需版本≥8.0.4且启用icu正则引擎,不支持pcre语法如(?i),应改用第四个参数如’i’(忽略大小写)、’m’(多行模式)等。

SQL 正则表达式高级使用实战

MySQL 8.0 里 REGEXP_LIKE 怎么写才不报错

MySQL 5.7 及更早版本压根不支持 REGEXP_LIKE,直接用会报 function REGEXP_LIKE does not exist。必须确认版本 ≥ 8.0.4,且默认启用正则引擎(一般没问题,但某些云厂商定制版可能关了)。

常见错误是把 PCRE 风格的写法直接搬过去,比如 d+(?i)abc —— MySQL 用的是 ICU 正则库,不支持 ?i 这类内联标志,得改用第四个参数:REGEXP_LIKE(col, 'abc', 'i')

  • 'i':忽略大小写;'c':区分大小写(默认);'m':多行模式(^/$ 匹配每行首尾)
  • 锚点 ^$ 默认只匹配整个字符串首尾,加 'm' 才能匹配换行符两侧
  • 不支持 Q...E 转义字面量,想匹配含正则元字符的字符串,得手动对 .*[ 等加反斜杠

postgresql~~* 到底怎么选

~ 是区分大小写的正则匹配操作符,~* 是忽略大小写的。别用 ILIKE 替代——它只支持简单通配(%/_),不支持正则。

性能上,~~* 快一截,尤其在有索引时。如果字段建了 text_pattern_opspg_trgm 索引,~ 能走索引,~* 大概率全表扫(除非你显式用 LOWER(col) ~ 'pattern' 并给 LOWER(col) 建函数索引)。

  • 要查邮箱本地部分是否含数字:email ~ '^[a-zA-Z]+[0-9]'::text
  • 想避免大小写陷阱又想索引友好:LOWER(email) ~ '^admin' + CREATE INDEX ON users (LOWER(email))
  • 别写 email ~* '^ADMIN'——看似省事,实际放弃索引加速机会

sqliteREGEXP 前必须干的三件事

SQLite 原生不带正则函数,REGEXP 是个占位符,必须靠外部扩展或自定义函数注入。直接执行 select * FROM t WHERE x REGEXP 'foo' 会报 no such function: REGEXP

常见做法是加载 libsqlite3-mod-regexplinux)或编译时加 -DSQLITE_ENABLE_REGEXP,但更可控的方式是用应用层注册函数。比如 Python 的 sqlite3 模块:conn.create_function('REGEXP', 2, Lambda pattern, text: re.search(pattern, text) is not None)

  • 自定义函数返回值必须是整数:0 表示不匹配,非 0 表示匹配(别返回 True/False
  • 正则引擎是 Python 的 re,不是 SQLite 内置的,所以支持 re.DOTALL 等标志,但要注意跨平台兼容性
  • 如果用的是 SQLCipher 或某些嵌入式环境,REGEXP 几乎肯定不可用,得改用 GLOBLIKE 将就

正则提取字段时,substring()regexp_replace() 别混用

想从字符串里抠出手机号,用 substring(col FROM 'd{11}')(PostgreSQL)或 REGEXP_SUBSTR(col, 'd{11}') (MySQL 8.0+);想删掉括号和空格,才用 regexp_replace()。混用会导致逻辑错乱,比如误把“匹配成功”当“提取结果”。

MySQL 的 REGEXP_SUBSTR 第二个参数是正则,第三个是位置(默认 1),第四个是出现序号(默认 1),第五个是匹配参数(如 'c')。漏掉第四个参数想取第二个匹配项?结果永远是第一个。

  • PostgreSQL 提取第二个括号内容:substring(col FROM '(([^)]+))' for 2)(注意 FOR 2 指子组编号)
  • MySQL 提取所有邮箱并拼成逗号串:REGEXP_REPLACE(col, '([^@]+@[^@]+.[^@]+)', '$1', 1, 0, 'g') —— 这里 'g' 很关键,否则只换第一个
  • SQLite 没 REGEXP_SUBSTR,只能靠自定义函数或先 REGEXP 判断再用 SUBSTR+INSTR 硬拆

最常被忽略的是:正则提取函数在 NULL 输入时大多返回 NULL,但有些数据库(如旧版 MySQL)会返回空字符串,导致后续 Length() 或拼接出错。检查前先 WHERE col IS NOT NULL 更稳妥。

text=ZqhQzanResources