position函数在postgresql/sql标准中语法为position('sub' in str),sqlite同;mysql不支持,需用locate('sub',str)或instr(str,'sub');返回值从1开始计数,未找到返回0,null输入导致结果为null,且默认大小写敏感。

POSITION 函数在不同数据库中的语法差异
POSITION 不是跨数据库统一的函数,PostgreSQL 和标准 SQL 用 POSITION(substring IN string),MySQL 则不支持这个写法,必须用 LOCATE() 或 INSTR();SQLite 支持 POSITION() 但要求参数顺序为 POSITION(needle IN haystack),和 PostgreSQL 一致。
常见错误是直接把 PostgreSQL 的写法复制到 MySQL 里,结果报错 FUNCTION database.POSITION does not exist。
- PostgreSQL:
SELECT POSITION('cat' IN 'concatenate');→ 返回4 - MySQL:
SELECT LOCATE('cat', 'concatenate');或SELECT INSTR('concatenate', 'cat'); - SQLite:
SELECT POSITION('cat' IN 'concatenate');
POSITION 返回值为 1 而不是 0 的原因
SQL 标准规定字符串索引从 1 开始,所以 POSITION 找到匹配时返回的是「第几个字符」,不是数组下标。这意味着空字符串或未匹配时返回 0,而首字符匹配就是 1 —— 这和大多数编程语言(如 Python 的 str.find())返回 0 起始的习惯冲突。
容易踩的坑:用 POSITION(...) > 0 判断存在性没问题,但若写成 POSITION(...) == 0 来判断“不在开头”,就逻辑错误,因为 0 只表示“没找到”,不是“不在位置 0”。
-
POSITION('a' IN 'abc')→1(不是 0) -
POSITION('x' IN 'abc')→0(不是 NULL) - 想判断是否包含子串,用
POSITION(...) > 0,别用!= 0混淆语义
嵌套使用 POSITION 提取中间字段的典型场景
当需要从固定分隔符格式的字符串中截取某一段(比如从 "name:value;age:25;city:beijing" 中取 city 的值),POSITION 常和 SUBSTRING 配合使用,但要注意两次 POSITION 的偏移计算。
关键点在于:第二个 POSITION 必须从第一个匹配位置之后开始搜索,否则会重复命中同一处分隔符。
- 找
city:起始位置:POSITION('city:' IN data) - 再找后续的
;位置:POSITION(';' IN SUBSTRING(data FROM POSITION('city:' IN data) + 5)) - 最终提取:
SUBSTRING(data FROM p1 + 5 FOR p2 - 1),其中p1是city:位置,p2是相对偏移后的分号位置
漏掉 + 5(即 'city:' 长度)会导致从开头重新搜索,取到第一个 ; 而不是 city 后面那个。
NULL 输入和大小写敏感性带来的隐性问题
POSITION 对 NULL 非常敏感:只要任一参数为 NULL,整个表达式返回 NULL,而不是 0。这在 JOIN 或 WHERE 条件中容易导致意外过滤——比如 WHERE POSITION(x IN y) > 0,如果 y 是 NULL 字段,这一行直接被排除,连日志都难察觉。
另外,POSITION 默认区分大小写,POSITION('A' IN 'abc') 返回 0,这点和某些正则函数不同,也不同于部分数据库的默认 collation 行为。
- 防 NULL:写成
POSITION(COALESCE(sub, '') IN COALESCE(str, '')) - 想忽略大小写:PostgreSQL 可先转小写
POSITION(LOWER(sub) IN LOWER(str));MySQL 用LOCATE(LOWER(sub), LOWER(str)) - 别依赖数据库默认排序规则来“自动”忽略大小写,显式转换更可靠
实际查数据时,经常发现 WHERE 条件莫名少了几百条,最后定位到某个字段含 NULL 或大小写不一致,POSITION 就静默失效了。










