LOCATE函数返回0表示未找到子串,非错误;位置从1开始计数,第三个参数为起始字符位置;大小写敏感性由字段collation决定;推荐用INSTR或POSITION提升可读性。

LOCATE 函数返回值为 0 表示没找到,不是 -1
很多人看到 LOCATE('a', 'hello') 返回 0 就以为出错了,其实这是正常行为——LOCATE 找不到子串时明确返回 0,和多数编程语言的 -1 习惯不同。这点不注意,容易把“没找到”误判成“在第 0 位”,导致逻辑错乱。
实际使用时得用 IF(LOCATE(...) > 0, ..., ...) 或 LOCATE(...) != 0 判断存在性,不能直接拿返回值当布尔用。
-
LOCATE('x', 'abc')→0(真没找到) -
LOCATE('a', 'abc')→1(从 1 开始计数,不是 0) - 想查是否包含子串?优先用
INSTR()(语义更直白)或LIKE '%x%',别只依赖返回值真假判断
第二个参数是起始位置,不是偏移量
LOCATE(sub, str, pos) 的第三个参数 pos 是「从第几个字符开始搜」,不是跳过几个字符。比如 LOCATE('o', 'hello world', 5) 是从第 5 个字符(即第一个 o)开始找,结果还是 5;而 LOCATE('o', 'hello world', 6) 才会找到后面的 o(位置 8)。
- 位置从 1 开始计数,
pos小于 1 会被当作 1 处理 -
pos超过字符串长度,直接返回0 - 想实现“跳过前 N 个字符再搜”,必须确保
pos是你要的起始下标,不是N+1这类换算结果
区分大小写取决于字段的 collation
LOCATE 本身不控制大小写,它完全遵循字段的排序规则(collation)。如果字段是 utf8mb4_0900_as_cs 或带 _cs 后缀,就是大小写敏感;如果是 _ci(case-insensitive),那 LOCATE('A', 'apple') 就会返回 1。
临时改行为可以用 BINARY 强制区分:
SELECT LOCATE(BINARY 'A', 'apple'); -- 返回 0
但要注意:BINARY 会让索引失效,线上大表慎用。
- 建表时就定好 collation,比运行时硬转更可靠
- 模糊查找场景(如后台搜索)通常需要
_ci,精确匹配才考虑_cs或BINARY - 不要靠
UPPER()/LOWER()包裹参数来“统一大小写”,性能差且可能破坏索引
替代方案:INSTR 和 POSITION 更易读
INSTR(str, sub) 是 LOCATE(sub, str) 的反序写法,语义更贴近“在 str 里找 sub”;POSITION(sub IN str) 则是标准 SQL 写法,可读性最强。三者功能完全等价,返回值规则也一致。
选哪个主要看团队习惯和 SQL 风格约束:
- 写跨数据库兼容 SQL?优先用
POSITION - 维护老 MySQL 项目?
INSTR更常见 - 用
LOCATE带起始位置时,别漏掉参数顺序——LOCATE(sub, str, pos)不是LOCATE(str, sub, pos)
真正容易被忽略的是:这些函数都不支持正则,要模糊定位(比如“找以数字开头的单词”)就得切到 REGEXP 或应用层处理。


















