mysql的instr(str, substr)返回子串首次出现位置(从1开始),未找到返回0;sql server用charindex(substr, str)且支持起始位置;postgresql用position(substr in str)或strpos(str, substr),均不支持起始偏移。

MySQL里用INSTR查字符位置,第一个参数是被搜索字符串
INSTR是MySQL的原生函数,语法为INSTR(str, substr),注意顺序:被搜索的字符串在前,要找的子串在后。这点和Python的str.find()一致,但和SQL Server相反。
常见错误是把参数顺序写反,比如写成INSTR('a', 'abc'),结果永远是0——因为你在“a”里找“abc”,显然找不到。
- 返回值从1开始计数,没找到返回0(不是-1)
- 区分大小写,
INSTR('Hello', 'h')返回0;需要忽略大小写时先用LOWER()统一转换 - 支持多字节字符,中文、emoji都能正常定位,例如
INSTR('你好world', 'wor')返回4
SQL Server必须用CHARINDEX,且参数顺序相反
CHARINDEX的签名是CHARINDEX(substring, string [, start_location]),子串在前,主串在后。这是和MySQL最易混淆的地方。
如果直接把MySQL的INSTR写法搬过去,比如CHARINDEX('abc', 'xyzabc'),逻辑是对的;但换成CHARINDEX('xyzabc', 'abc')就完全错了——后者是在“abc”里找“xyzabc”,必然返回0。
- 返回值也是从1开始;没找到返回0
- 第三个可选参数
start_location指定起始搜索位置,比如CHARINDEX('o', 'hello world', 5)跳过前4个字符,返回8(第二个o) - 不区分大小写取决于数据库排序规则(collation),通常默认不敏感;如需强制敏感,可用
COLLATE SQL_Latin1_General_CP1_CS_AS
PostgreSQL没有INSTR或CHARINDEX,得用POSITION或STRPOS
PostgreSQL用POSITION(substr IN str),语法接近自然语言,但注意它用IN关键字连接两个参数,不能写逗号。另一个等价函数是STRPOS(str, substr),参数顺序又回到MySQL风格。
容易踩的坑是混用语法:POSITION('x', 'abc')会报错,必须写成POSITION('x' IN 'abc');而STRPOS('abc', 'x')才合法。
-
POSITION和STRPOS都返回从1开始的位置,未找到返回0 - 它们都不支持指定起始偏移,如需跳过前N位,得配合
SUBSTRING,例如POSITION('o' IN SUBSTRING('hello', 3)) + 2 - 大小写敏感行为同数据库LC_COLLATE设置,一般建议显式用
ILIKE或LOWER()处理
跨数据库写法不可行,别试图用宏或通用包装函数
不同数据库对“查找位置”这个操作的函数名、参数顺序、空值/未找到的返回值定义全部不一致,强行抽象成一个SQL宏只会让逻辑更难读、更难调。
实际项目中,与其花时间封装,不如在应用层做适配:比如Go里写func findPos(dbType string, s, sub string) int,内部按类型分发到对应SQL模板;或者在ORM的方言模块里统一处理。
还有个隐形陷阱:所有这些函数都只返回第一次出现的位置。如果要找第n次,MySQL需嵌套INSTR,SQL Server要用CHARINDEX配合SUBSTRING循环截取,PostgreSQL则得靠regexp_matches——这不是一个函数能解决的事。










