在处理数据库中的文本字段时,经常需要知道某个子字符串在原始字符串中第一次出现的位置,比如从邮箱地址中提取域名、解析路径中的文件名、判断日志内容里是否包含特定关键字等。不同数据库提供了不同的定位函数,其中MySQL中的LOCATE和SQL Server中的CHARINDEX是最常用的两个。本文详细介绍这两个函数的语法、返回值规则以及实际应用场景。

一、MySQL中的LOCATE函数
LOCATE是MySQL提供的子字符串定位函数,它返回子字符串在目标字符串中首次出现的位置,位置从1开始计数。如果找不到子字符串,返回0;如果任一参数为NULL,则返回NULL。它的标准语法有两种形式:
-- 形式一:两个参数 LOCATE(substr, str) -- 形式二:三个参数,pos表示从哪个位置开始搜索 LOCATE(substr, str, pos)
注意参数顺序是子字符串在前,目标字符串在后,这一点和SQL Server的CHARINDEX正好相反,也是跨数据库开发时最容易混淆的地方。举个例子:LOCATE('@', 'admin@ipipp.com')会返回7,因为@符号第一次出现在第7个字符的位置。
三参数形式在实际中非常有用。比如要找出字符串中第二次出现的位置,可以先定位第一次出现的位置,然后从它的下一位继续搜索:
SELECT LOCATE('a', 'banana') AS first_pos; -- 返回 2
SELECT LOCATE('a', 'banana', LOCATE('a', 'banana') + 1) AS second_pos; -- 返回 4如果只是想判断某个字段是否包含关键字,LOCATE的返回值可以直接用在WHERE条件里,也可以结合INSTR或者LIKE使用。不过要提醒一句,对字段使用函数会导致索引失效,在大表上做这类查询时需要考虑性能影响。
二、SQL Server中的CHARINDEX函数
CHARINDEX是SQL Server对应的定位函数,功能类似但参数顺序相反。它的语法是CHARINDEX(expressionToFind, expressionToSearch, start_location),即要查找的内容在前,被搜索的字符串在后,第三个参数是可选的起始位置。返回值规则和LOCATE基本一致:找不到返回0,参数为NULL返回NULL。
SELECT CHARINDEX('@', 'admin@ipipp.com') AS pos; -- 返回 7
SELECT CHARINDEX('a', 'banana', 3) AS pos; -- 从位置3开始找,返回 4CHARINDEX经常和SUBSTRING配合使用来拆分字符串。比如从一个完整邮箱中取出域名部分,思路是先定位@符号的位置,再从它的下一位截取到字符串末尾。SQL Server中可以用LEN函数获取总长度:
DECLARE @email VARCHAR(100) = 'admin@ipipp.com';
SELECT
SUBSTRING(@email, CHARINDEX('@', @email) + 1, LEN(@email)) AS domain;
-- 结果为 ipipp.com这个模式在数据清洗场景中非常常见,例如从文件路径中提取文件名、从URL中提取参数、从编码字段中提取编号段,本质上都是先定位分隔符再截取的思路。
三、两个函数的关键差异与常见坑
虽然两个函数解决的问题相同,但细节差异需要牢记。首先是参数顺序:LOCATE是LOCATE(substr, str),CHARINDEX是CHARINDEX(substr, str),看起来写法一致,但如果你在SQL Server里习惯性写了MySQL风格,函数不会报语法错误,却可能返回0,因为参数含义完全变了。其次是兼容性:SQL Server较新版本同时也支持CHARINDEX的常规用法,而MySQL中没有CHARINDEX,SQL Server中也没有LOCATE(但SQL Server提供PATINDEX作为补充,它支持通配符模式匹配)。
另一个容易忽略的点是大小写处理。MySQL默认排序规则不区分大小写,所以LOCATE('ABC', 'abc')通常返回1;而SQL Server的默认排序规则也可能不区分大小写,但如果字段或数据库设置了区分大小写的排序规则,结果就会不同。如果业务上需要明确的大小写行为,最好在查询前确认排序规则设置。
最后是多字节字符问题。对于中文等包含多字节字符的字符串,两个函数都按字符而非字节计数(前提是使用对应的字符集类型,如MySQL的utf8mb4),因此中文算作一个位置单位。下面用一个综合例子演示在MySQL中提取URL的域名部分:
SELECT
SUBSTRING(
url,
LOCATE('//', url) + 2,
LOCATE('/', url, LOCATE('//', url) + 2) - LOCATE('//', url) - 2
) AS domain
FROM web_pages;这个写法先定位协议分隔符,再找到域名结束的第一个斜杠,最后计算出截取长度,是LOCATE嵌套使用的典型场景。掌握位置定位加子串截取这一组合,基本可以应对SQL中绝大部分字符串解析需求。