POSITION是标准SQL函数,语法为POSITION('substr' IN string),仅PostgreSQL原生支持;CHARINDEX是SQL Server特有函数,语法为CHARINDEX('substr', string[, start_location]),支持起始位置参数且仅限SQL Server和Azure SQL使用。

POSITION 和 CHARINDEX 的本质区别
POSITION 是标准 SQL(如 PostgreSQL、MySQL 8.0+、SQL:2003)函数,语法是 POSITION('substr' IN string);CHARINDEX 是 SQL Server 和 Sybase 特有函数,语法是 CHARINDEX('substr', string[, start_location])。二者都返回子串首次出现的起始位置(从 1 开始计数),但不兼容——在 PostgreSQL 里用 CHARINDEX 会报错 function charindex does not exist,反之在 SQL Server 里 POSITION 直接不可识别。
-
POSITION不支持指定搜索起始偏移,只能从头找 -
CHARINDEX第三个参数可选,允许跳过前 N 个字符再搜,适合循环定位或找第二次出现的位置 - 二者对空字符串行为一致:
POSITION('' IN 'abc')和CHARINDEX('', 'abc')都返回 1
常见错误:位置为 0 或 NULL 时的含义混淆
这两个函数在子串未找到时,返回值不同但容易误读:
-
POSITION返回 0(不是 NULL) -
CHARINDEX也返回 0(不是 -1 或 NULL)
这意味着不能用 IS NULL 判断是否找到,而必须显式比较 = 0:
SELECT * FROM logs
WHERE POSITION('ERROR' IN message) = 0; -- 正确:筛选不含 'ERROR' 的记录
<p>SELECT * FROM logs
WHERE CHARINDEX('WARN', message) > 0; -- 正确:筛选含 'WARN' 的记录如果写成 WHERE POSITION(...) IS NULL,查询永远不匹配——因为 POSITION 永远不会返回 NULL。
替代方案:当需要跨数据库兼容时怎么办
没有直接等价的跨库函数,但可用表达式模拟基本功能:
- 在 MySQL 中,
LOCATE('substr', string)行为接近POSITION,且支持三参数形式(LOCATE('s', str, pos)),比POSITION更灵活 - 在 PostgreSQL 中,想实现类似
CHARINDEX(..., ..., start)的效果,得组合STRPOS(SUBSTRING(string FROM start), 'substr'),再加偏移修正 - 如果只是判断存在性(不关心位置),统一用
string LIKE '%substr%'最安全,但无法获取索引值
注意:所有这些函数都不支持正则定位,要找模式匹配位置,得用 REGEXP_INSTR(MySQL 8.0+、Oracle)或 REGEXP_MATCHES + REGEXP_REPLACE 组合(PostgreSQL),性能和语义差异更大。
实际使用中容易被忽略的细节
- 大小写敏感性取决于字段排序规则(collation):在 SQL Server 默认大小写不敏感,PostgreSQL 默认敏感;
POSITION('a' IN 'ABC') 在 PostgreSQL 返回 0,在 SQL Server 返回 1
-
CHARINDEX 的第三个参数若超出字符串长度,返回 0(不是报错)
-
POSITION 的子串参数不能是 NULL,否则整个表达式结果为 NULL;而 CHARINDEX(NULL, ...) 在 SQL Server 中直接返回 NULL,需提前 ISNULL 或 COALESCE 处理
- 用位置做字符串截取时(比如
SUBSTR(str, pos, len)),务必确认 pos ≠ 0,否则可能截出空值或触发越界警告(尤其在严格模式下)
POSITION('a' IN 'ABC') 在 PostgreSQL 返回 0,在 SQL Server 返回 1CHARINDEX 的第三个参数若超出字符串长度,返回 0(不是报错)POSITION 的子串参数不能是 NULL,否则整个表达式结果为 NULL;而 CHARINDEX(NULL, ...) 在 SQL Server 中直接返回 NULL,需提前 ISNULL 或 COALESCE 处理SUBSTR(str, pos, len)),务必确认 pos ≠ 0,否则可能截出空值或触发越界警告(尤其在严格模式下)位置函数看着简单,但跨环境移植、边界值处理、collation 依赖这三点,最容易在上线后突然暴露问题。

















