patindex不是正则引擎,仅支持like风格通配符(%、_、[abc]、1),不支持\d、+、{2,5}、\b等正则特性;模式必须以%开头,返回1-based位置,未匹配返回0,null输入才返回null。0-9 ↩

PATINDEX不是正则引擎,只支持LIKE风格通配符
PATINDEX 在 SQL Server 中根本不能执行正则表达式匹配——它只认 %、_、[abc]、[^0-9] 这类 LIKE 通配符,不支持 \d、+、{2,5}、\b 或捕获组。写 PATINDEX('%[0-9]{3}%', @s) 看似像正则,实际 {3} 被当字面量处理,永远返回 0。
常见误用场景包括:
- 想匹配“以数字开头”却写成
PATINDEX('^[0-9]%', @s)——^在方括号外无效,开头必须是% - 想跳过大小写敏感问题,直接套用
REGEXP思路,结果语法报错或逻辑失效 - 把
PATINDEX('%cat%', 'scatter')当作单词匹配,实际会命中(无词界概念)
正确写法:% 必须出现在 pattern 两端,字符类用方括号
PATINDEX 的 pattern 参数强制要求以 % 开头(极少数例外:搜索首字符可用 'x%',末字符可用 '%x'),否则不匹配。真正能工作的模式只有展开式、非贪婪的有限组合。
实用写法示例:
- 查含任意数字:
PATINDEX('%[0-9]%', col) > 0 - 查含非数字/字母/空格字符:
PATINDEX('%[^ 0-9A-Za-z]%', col) > 0 - 查是否为纯数字(不含小数点或符号):
PATINDEX('%[^0-9]%', col) = 0(注意等于 0 表示没找到“非法字符”,即全合法) - 查是否含连续三位数字:
PATINDEX('%[0-9][0-9][0-9]%', col) > 0,不能缩写 - 区分大小写时加
COLLATE:PATINDEX('%[a-z]%', col COLLATE Latin1_General_CS_AS) > 0
返回值是 1-based 位置,0 ≠ NULL,NULL 需单独处理
PATINDEX 找到时返回从 1 开始的位置索引(不是 0),没找到时返回 0,而输入字段为 NULL 时才返回 NULL。这两者语义完全不同,混用会导致查询漏数据或报错。
典型陷阱:
- 写
WHERE PATINDEX('%[0-9]%', col) IS NOT NULL—— 实际上只要 col 不为 NULL,该表达式永远为真(因为返回 0,不是 NULL) - 写
WHERE PATINDEX('%[0-9]%', col) != 0—— 看似对,但若 col 是 NULL,整个表达式结果为 UNKNOWN,该行被过滤掉(三值逻辑),可能意外丢失记录 - 正确做法是显式判断:
WHERE col IS NOT NULL AND PATINDEX('%[0-9]%', col) > 0 - 或封装防 NULL:
WHERE ISNULL(PATINDEX('%[0-9]%', col), 0) > 0
性能与兼容性:别在 WHERE 条件里高频用,跨库方案要换思路
PATINDEX 无法利用索引,扫描开销大,尤其在 VARCHAR(MAX) 或 TEXT 字段上 + 复杂 pattern 时,性能明显低于 CHARINDEX。SQL Server 2025 起虽新增了正则函数(如 REGEXP_LIKE),但仍是预览特性,生产环境慎用。
跨数据库迁移时要注意:
- MySQL 8.0+ 用
REGEXP_INSTR(col, 'pattern'),不支持PATINDEX - PostgreSQL 用
POSITION('literal' IN col)(仅字面)或SUBSTRING(col FROM 'regex')配合长度推算位置 - SQLite 没等效函数,必须由应用层解析
- 如果业务逻辑依赖复杂模式(如邮箱、身份证、带分隔符的编号),别硬套
PATINDEX—— 改用应用代码做正则匹配,SQL 层只做简单存在性判断
真正容易被忽略的是排序规则影响:同一 pattern 在 Latin1_General_CI_AS 和 Latin1_General_BIN 下可能返回不同位置,尤其涉及重音字符、全半角或大小写混合时,不显式指定 COLLATE 就上线,线上行为可能和测试不一致。










