
MySQL里用LOCATE找子串第一次出现的位置
MySQL不支持CHARINDEX,得用LOCATE。它返回子串在字符串中首次出现的起始位置(从1开始计数),找不到就返回0。
常见错误是传参顺序搞反:LOCATE(substring, string),不是反过来。比如LOCATE('abc', 'xabcx')返回2;但写成LOCATE('xabcx', 'abc')就永远是0。
- 第三个参数可选,表示从第几个字符开始搜索,比如
LOCATE('a', 'banana', 3)返回4(跳过前两个字符) - 区分大小写取决于字段或数据库的collation,若需忽略大小写,先用
LOWER()统一转换 - 空字符串
''作为子串时,LOCATE在MySQL 8.0+返回1,旧版本行为不一致,尽量避免
SQL Server必须用CHARINDEX,不能用LOCATE
SQL Server不认识LOCATE,一用就报错:Invalid column name 'LOCATE' 或直接提示函数不存在。唯一正解是CHARINDEX,语法是CHARINDEX(substring, string[, start_location])。
和LOCATE不同,CHARINDEX返回位置从1开始,没找到也返回0,这点一致;但参数顺序一样,都是子串在前、主串在后。
- 如果
substring为NULL,整个结果就是NULL,不是0——这是最容易踩的坑,查不到时别只检查是否等于0 - start_location为0会被当作1处理;负数或超长值会自动截断到有效范围
- 搜索中文、emoji等多字节字符完全没问题,不需要额外编码处理
PostgreSQL和SQLite怎么处理
PostgreSQL没有LOCATE或CHARINDEX,得用POSITION函数:POSITION('sub' IN 'string'),返回从1开始的位置,没找到返回0。注意语法是IN关键字,不是逗号分隔。
SQLite默认也不支持这两个函数,但多数现代发行版编译时启用了extension-functions,才可能有instr()——它的行为接近CHARINDEX(子串在前,主串在后),返回从1开始的位置。
- PostgreSQL的
POSITION不支持起始偏移,要实现类似功能得结合SUBSTRING和LENGTH - SQLite的
instr在原生build里常被禁用,执行时报no such function: instr,得确认环境或改用LIKE+ 循环模拟 - 三者对空格、不可见字符(如
\t、\n)都敏感,匹配前建议用TRIM或REPLACE预处理
跨数据库写法兼容性差,别硬套一个函数名
想写一次SQL跑遍MySQL、SQL Server、PostgreSQL?基本做不到。LOCATE在SQL Server报错,CHARINDEX在MySQL报错,POSITION在SQL Server根本不存在。
如果业务逻辑真需要位置信息,更稳妥的做法是:在应用层做字符串查找(Python的str.find()、Go的strings.Index()),或者把逻辑拆到视图/存储过程中,按数据库分别实现。
- 用ORM时,有些框架(如Django ORM、SQLAlchemy)封装了跨库位置函数,但底层仍是条件编译,不是真统一
- 千万别在WHERE里嵌套复杂位置计算还加索引期望加速——这类表达式几乎无法走索引,性能会断崖下跌
- 最隐蔽的问题:某些数据库对超长字符串(如TEXT字段)调用位置函数时会静默截断,返回结果与预期不符,务必用
LENGTH()先校验长度










