charindex返回子串首次出现的1-based位置,未找到返回0而非-1;第三参数指定搜索起始位置,越界或非法值返回0;参数为null时结果为null。

CHARINDEX 返回什么值?0 和 -1 有区别吗
CHARINDEX 在 SQL Server 中返回子字符串首次出现的起始位置(从 1 开始计数),找不到时返回 0,不是 -1。这点和很多编程语言(如 JavaScript 的 indexOf)不同,容易误判为“-1 表示未找到”而写错逻辑。
常见错误是用 IF CHARINDEX(...) = -1 判断失败,结果永远不进分支。正确写法是:
IF CHARINDEX('abc', @str) = 0
PRINT 'not found'
注意:CHARINDEX 区分大小写与否取决于数据库或列的排序规则(collation),不是函数自身行为;若需强制不区分,可显式指定,例如:
CHARINDEX('ABC', @str, 1) COLLATE SQL_Latin1_General_CP1_CI_AS
CHARINDEX 的第三个参数是做什么的
第三个参数是搜索起始位置(整数),默认为 1。它不表示“跳过前 N 个字符”,而是从第 N 个字符开始向后找——这个细节常被忽略,导致定位偏移。
比如:
DECLARE @s NVARCHAR(20) = 'hello world hello';
SELECT CHARINDEX('hello', @s, 7); -- 返回 13,不是 1
因为从第 7 个字符(即空格后)开始搜,第二次 'hello' 才被命中。
- 起始位置超出字符串长度,直接返回
0 - 传入负数或
NULL,整个表达式返回NULL - 该参数对性能影响极小,但用于分段提取(如取第二个分隔符之后的内容)很实用
用 CHARINDEX 配合 SUBSTRING 提取中间字段是否安全
常见做法是:先用 CHARINDEX 找到两个分隔符位置,再用 SUBSTRING 截取。但必须检查所有 CHARINDEX 结果是否为 0,否则 SUBSTRING 会抛出错误或返回意外空值。
例如提取 JSON 风格字符串中的 "name":"xxx" 的值部分:
DECLARE @json NVARCHAR(100) = '"name":"Alice","age":30';
DECLARE @start INT = CHARINDEX('":"', @json) + 3;
DECLARE @end INT = CHARINDEX('","', @json, @start);
<p>-- 错误:没检查 @start 或 @end 是否为 0,SUBSTRING 就可能崩溃
SELECT SUBSTRING(@json, @start, @end - @start);</p>
安全写法要加判断:
- 用
NULLIF把0转成NULL,避免SUBSTRING接收非法长度 - 或用
CASE WHEN CHARINDEX(...) > 0 THEN ... ELSE NULL END - 注意:SQL Server 2016+ 更推荐用
STRING_SPLIT或JSON_VALUE处理结构化文本,CHARINDEX+SUBSTRING是兜底方案
CHARINDEX 在 WHERE 条件里能走索引吗
不能——除非是前导匹配且用了 LIKE 'prefix%' 这类可利用索引的形式。CHARINDEX(col, 'x') > 0 或 CHARINDEX('x', col) > 0 都会导致全表扫描。
如果你常按子串查数据,应该考虑:
- 增加计算列 + 索引,例如
ALTER TABLE t ADD has_tag AS CASE WHEN CHARINDEX('urgent', note) > 0 THEN 1 ELSE 0 END,再对has_tag建索引 - 用全文索引(
CONTAINS/FREETEXT)替代 - 把标签类数据拆到关联表,用规范的
JOIN查
硬用 CHARINDEX 在大表 WHERE 里过滤,性能下降往往比预想中更早出现——几百万行就可能明显卡顿。










