charindex返回0表示未找到子串,参数顺序为“子串、源字符串、起始位置(从1开始)”,区分排序规则,不支持通配符;patindex支持通配符但性能较差。

CHARINDEX 返回值为 0 表示没找到,不是 -1
SQL Server 的 CHARINDEX 和 JavaScript 的 indexOf 行为最常被混淆的点就在这里:找不到子串时,CHARINDEX 返回 0,而多数编程语言返回 -1。直接拿 IF CHARINDEX(...) > 0 判断存在性没问题,但若你写成 IF CHARINDEX(...) = -1,永远不成立。
常见错误场景:
- 把前端逻辑照搬进 T-SQL,比如写
WHERE CHARINDEX('abc', col) == -1(语法错且逻辑错) - 用
CHARINDEX做条件排序时误判位置,比如ORDER BY CHARINDEX('x', col),结果把没匹配的全排在最前(因为都是 0)
CHARINDEX 的参数顺序是「要找的,被找的,起始位置」
和 indexOf(searchStr, fromIndex) 不同,CHARINDEX 的第一个参数是子串(search_string),第二个才是源字符串(expression),第三个可选——起始位置从 1 开始计数,不是 0。
实操建议:
- 别记成“类似 JS”,硬记顺序:查什么、在哪查、从哪查
- 起始位置省略时默认为 1;设为
0会报错,设为NULL返回NULL - 想从第 5 个字符开始找,写
CHARINDEX('x', col, 5),不是4
示例:SELECT CHARINDEX('o', 'hello world', 5) → 返回 8(第二个 o)SELECT CHARINDEX('o', 'hello world', 6) → 返回 8(仍从位置 6 往后找,第一个匹配仍是第 8 位)
CHARINDEX 区分排序规则,可能因 collation 导致大小写/重音敏感
它不像 INSTR(MySQL)或 POSITION(PostgreSQL)那样默认忽略大小写——实际行为完全取决于字段或数据库的排序规则(collation)。如果字段是 SQL_Latin1_General_CP1_CI_AS(CI = case-insensitive),CHARINDEX('A', 'apple') 就能命中;但如果是 _CS_AS(CS = case-sensitive),就返回 0。
容易踩的坑:
- 开发环境用 CI 排序规则,测试通过;上线后生产库是 CS,查询突然失效
- 跨数据库迁移时没检查 collation,
CHARINDEX结果不一致 - 临时解决大小写问题不要用
UPPER()包裹两边(性能差),优先改字段 collation 或加COLLATE子句
稳妥写法:CHARINDEX('a', col COLLATE SQL_Latin1_General_CP1_CI_AS)
替代方案:用 PATINDEX 处理通配符,但性能更差
如果真需要类似 indexOf 的模糊能力(比如“找以 x 开头的单词”),CHARINDEX 不行,得换 PATINDEX('%x%', col)。但它底层走的是模式扫描,无法利用索引,数据量大时明显变慢。
使用前提:
-
PATINDEX第一个参数必须是字符串字面量或变量,不能是列名 - 支持
%、_、[abc]等,但不支持正则(SQL Server 2017+ 才有STRING_SPLIT+ CLR 正则) - 同样返回
0表示未匹配,起始位置也是从 1 开始
简单对比:CHARINDEX('test', col) → 精确匹配,快PATINDEX('%test%', col) → 模糊匹配,慢,慎用于 WHERE 条件
CHARINDEX 只存在于 SQL Server 和 Azure SQL;PostgreSQL 用 POSITION 或 STRPOS,MySQL 用 INSTR,它们的参数顺序、返回值含义都不同——别假设通用。











