CHARINDEX返回值基于1,非0;参数顺序为子串、主串、起始位置;返回0表示未找到,NULL仅当参数为NULL;需用>0判断存在,避免与NULL混淆,并注意排序规则影响大小写匹配。

CHARINDEX 返回值是 1-based,不是 0-based
很多人看到 CHARINDEX('a', 'abc') 返回 1 就下意识觉得“错了”,其实这是对的——SQL Server 所有位置函数都从 1 开始计数。写 WHERE 条件时别用 CHARINDEX('x', col) != 0,虽然逻辑成立,但语义不清;推荐统一用 CHARINDEX('x', col) > 0 表达“存在”。
常见错误现象:SUBSTRING(col, CHARINDEX('-', col), 5) 在字段不含 - 时会报错,因为 CHARINDEX 返回 0,导致起始位置为 0(SUBSTRING 不接受 0 起始)。
- 正确做法:用
NULLIF(CHARINDEX('-', col), 0)把 0 转成 NULL,再配合ISNULL(..., 1)或直接用CASE WHEN - 空字符串
''作为第一个参数时,CHARINDEX('', 'abc')永远返回 1,不是报错,也不是遍历匹配 - 主串为
NULL时,整个表达式结果就是NULL,不会因第三个参数存在而改变
参数顺序容易和 MySQL 的 INSTR 搞反
CHARINDEX 是 CHARINDEX(子串, 主串[, 起始位置]),和 MySQL 的 INSTR(主串, 子串) 完全相反。从其他数据库迁移脚本时,一眼扫过去觉得“都是找位置”,一粘贴就失效。
典型翻车现场:CHARINDEX(col, 'keyword') —— 这是在拿整列当子串去搜字面量 'keyword',几乎必然返回 0。
- 记法:T-SQL 里 “C-H-A-R” 开头,强调“查字符(
char)在哪(index)”,所以先写要查的字符/子串 - 第三个参数
start_location超出主串长度时,直接返回 0,不报错 - 想查第二次出现的位置?
CHARINDEX只找第一次,得靠递归 CTE 或自定义函数
大小写敏感性由排序规则决定,不是函数本身控制
CHARINDEX 本身不带 CI(case-insensitive)或 CS(case-sensitive)开关,它完全服从当前上下文的排序规则(collation)。字段是 Latin1_General_CS_AS,CHARINDEX('A', 'abc') 就返回 0;换成 SQL_Latin1_General_CP1_CI_AS 就返回 1。
临时强制不区分大小写:CHARINDEX('a', col COLLATE SQL_Latin1_General_CP1_CI_AS);强制区分:CHARINDEX('A', col COLLATE Latin1_General_CS_AS)。
- 排序规则冲突可能报错:“Cannot resolve collation conflict”,建议字面量和字段显式用相同 collation
- 别指望
UPPER()或LOWER()包裹来绕过——在非 Unicode 字段上可能丢失字符,且性能更差 -
CHARINDEX不支持通配符,传入'%a%'就按字面三个字符去找
WHERE 中判断“包含”必须显式比较 > 0
CHARINDEX 返回 0 表示“没找到”,返回 NULL 只有一种情况:任一参数为 NULL。所以 WHERE CHARINDEX('x', col) IS NOT NULL 会漏掉所有不含 x 的非 NULL 行——因为它们返回的是 0,不是 NULL。
正确写法只有两种:WHERE CHARINDEX('x', col) > 0 或等价的 WHERE col LIKE '%x%'(后者可走索引,前者不能)。
- 字段为
NULL时,CHARINDEX结果恒为NULL,需前置过滤:WHERE col IS NOT NULL AND CHARINDEX('x', col) > 0 - 如果字段含大量 NULL,
COALESCE(col, '')会把 NULL 转为空字符串,但要注意空字符串行为(返回 1)是否符合业务预期 - 跨库兼容需求强的场景,别硬套
CHARINDEX,优先考虑在应用层处理,或用CASE WHEN @@VERSION LIKE '%Microsoft%' THEN ... ELSE ... END分支兜底

















