charindex是sql server特有函数,语法为charindex(子串, 字符串[, 起始位置]),返回1-based位置或0(未找到);position是标准sql函数,仅postgresql原生支持,语法为position('子串' in 字符串),同样返回1-based位置或0。

CHARINDEX 和 POSITION 都能定位子字符串位置,但语法、行为和兼容性完全不同——别混用,也别指望它们在所有数据库里都能用。
CHARINDEX 只在 SQL Server 和 Azure SQL 中有效
这是 T-SQL 特有的函数,PostgreSQL、MySQL、Oracle 都不认它。调用时必须传两个参数:CHARINDEX(要找的子串, 原字符串),第三个参数(起始位置)可选,默认从 1 开始。
- 返回值是整数:找到则返回第一个匹配位置(从 1 计数);没找到返回 0
- 区分大小写取决于数据库排序规则(
COLLATE可临时覆盖) - 如果子串为空字符串
'',SQL Server 会返回 1(不是错误) - 示例:
CHARINDEX('abc', 'xabcx')→ 返回2;CHARINDEX('xyz', 'xabcx')→ 返回0
POSITION 是标准 SQL 函数,但 PostgreSQL/Standard SQL 用得多
SQL 标准定义了 POSITION,PostgreSQL 完全支持;MySQL 不支持,Oracle 用 INSTR 替代,SQL Server 完全不识别。
- 语法是
POSITION('子串' IN 字段),注意IN关键字不能省,顺序不能反 - 同样从 1 开始计数,未找到时返回 0(不是 NULL)
- 区分大小写,且对多字节字符(如中文)正常工作,不依赖隐式转换
- 示例:
POSITION('bc' IN 'abcde')→ 返回2;POSITION('xyz' IN 'abcde')→ 返回0
跨数据库安全定位子串位置的替代方案
如果代码要兼容多个数据库,别硬套 CHARINDEX 或 POSITION。更稳妥的做法是用条件表达式 + 数据库特有函数兜底:
- PostgreSQL:优先用
POSITION,或STRPOS(返回 0 表示未找到,行为一致) - MySQL:必须用
LOCATE(LOCATE('sub', field))或INSTR(INSTR(field, 'sub'),注意参数顺序相反) - Oracle:用
INSTR(INSTR(field, 'sub'),也是字段在前) - SQL Server:只能用
CHARINDEX,别尝试POSITION,会直接报错Incorrect syntax near 'POSITION'
容易被忽略的边界情况
位置函数看似简单,但实际用错常导致 WHERE 条件失效或数据漏查:
- 返回 0 表示“没找到”,不是 NULL —— 所以
WHERE CHARINDEX('x', col) > 0才等价于col LIKE '%x%',写成IS NOT NULL就全错了 - 空字符串
''在不同数据库中表现不一:SQL Server 返回 1,PostgreSQL 的POSITION('' IN col)报错,MySQL 的LOCATE('', col)返回 1 - 如果字段为 NULL,所有函数都返回 NULL(不是 0),需提前用
COALESCE(col, '')或WHERE col IS NOT NULL过滤
真正麻烦的不是记哪个函数怎么写,而是当一个查询要从 SQL Server 迁到 PostgreSQL 时,CHARINDEX 不仅要改成 POSITION,连参数顺序、空串处理、NULL 行为都要重新核对——这些细节往往拖慢迁移节奏。











