INSTR函数本身不支持查找最后一次出现的位置,只能从左往右返回首次匹配位置;需用REVERSE+INSTR+LENGTH组合换算:LENGTH(str)-LENGTH(substr)-INSTR(REVERSE(str),REVERSE(substr))+2。

INSTR函数本身不支持查找最后位置
MySQL的INSTR只从左往右搜索,返回首次匹配的起始位置(从1开始),没有内置参数控制“从右往左”或“最后一次出现”。想用INSTR直接找最后位置是不可能的——它压根不提供该能力。
用REVERSE + INSTR组合模拟“最后出现”
核心思路是:把原字符串和子串都翻转,用INSTR找翻转后**首次出现**的位置,再换算回原字符串中的末次位置。注意长度计算要小心边界。
- 假设原字符串为
str,子串为substr,且substr非空、存在 - 先算
REVERSE(str)中REVERSE(substr)的首次位置:INSTR(REVERSE(str), REVERSE(substr)) - 末次位置 =
LENGTH(str) - LENGTH(substr) - INSTR(REVERSE(str), REVERSE(substr)) + 2 - 更稳妥写法(避免空结果报错):
SELECT LENGTH(str) - LENGTH(substr) - INSTR(REVERSE(str), REVERSE(substr)) + 2 AS last_pos FROM (SELECT 'hello world hello' AS str, 'hello' AS substr) t WHERE INSTR(str, substr) > 0;
用LOCATE配合负偏移(MySQL 8.0+)更简洁
MySQL 8.0起,LOCATE支持第三个参数(起始位置),结合负数逻辑可反向逼近。但注意:它不原生支持负偏移,所以仍需借助REVERSE,不过封装成函数更清晰。
- 直接手写表达式依然推荐上一节的
REVERSE方案,稳定兼容所有MySQL版本 - 若频繁使用,可建自定义函数:
DELIMITER $$ CREATE FUNCTION LAST_INSTR(str TEXT, substr TEXT) RETURNS INT READS SQL DATA DETERMINISTIC BEGIN IF substr = '' OR str IS NULL OR substr IS NULL THEN RETURN 0; END IF; RETURN IF(INSTR(str, substr) = 0, 0, LENGTH(str) - LENGTH(substr) - INSTR(REVERSE(str), REVERSE(substr)) + 2); END$$ DELIMITER ; - 调用:
SELECT LAST_INSTR('abcabcab', 'ab');→ 返回7
PostgreSQL或SQL Server用户别套用INSTR
MySQL的INSTR是特有函数,PostgreSQL用POSITION或STRPOS,SQL Server用CHARINDEX,它们都不直接支持末次查找。PostgreSQL可用STRPOS(REVERSE(), ...)同理推导;SQL Server建议用REVERSE + CHARINDEX + LEN组合,公式结构一致,但函数名和空值处理细节不同。
真正容易被忽略的是:所有这类翻转方案在子串含多字节字符(如中文、emoji)时完全正常,因为LENGTH和REVERSE在MySQL中按字节操作,而UTF-8下中文占3字节——只要你的列是utf8mb4且连接字符集正确,就无需额外编码转换。但若混用latin1列和中文数据,REVERSE会把多字节拆开,结果彻底错乱。










