SUBSTRING函数在不同数据库中参数顺序一致(字符串、起始位置、长度),但函数名和负索引支持不同:MySQL支持负起始位,PostgreSQL和SQL Server不支持;起始位置从1开始,非0。

SUBSTRING 函数的基本用法和参数顺序
SUBSTRING 在不同数据库中行为一致,但函数名和参数顺序有差异,容易写错。MySQL 和 PostgreSQL 用 SUBSTRING(str, pos, len),SQL Server 支持 SUBSTRING(str, start, length) 和 LEFT/RIGHT 等等价写法,而 Oracle 用 SUBSTR(str, pos, len)(注意是两个 S)。关键点:起始位置从 1 开始,不是 0 —— 这是新手最常踩的坑,写成 SUBSTRING(text, 0, 5) 在 MySQL 中会返回空字符串,而不是前 5 个字符。
常见错误现象:SUBSTRING(name, 0, 3) 返回空值;SUBSTRING(email, -5, 5) 在 SQL Server 中报错(不支持负索引),但在 MySQL 中会被当作从末尾倒数第 5 位开始截取(MySQL 支持负起始位置)。
- MySQL / MariaDB:支持负
pos,SUBSTRING('hello', -2, 2)→lo - PostgreSQL:不支持负位置,需改用
SUBSTRING(text FROM length - n + 1 FOR n) - SQL Server:只支持正整数
start,负值直接报错
从邮箱地址中提取用户名(@ 前部分)
这是典型「按分隔符截取」场景,不能硬写固定长度,得结合 CHARINDEX(SQL Server)、LOCATE(MySQL)或 POSITION(PostgreSQL)动态定位 @ 的位置。
MySQL 示例:
SELECT SUBSTRING(email, 1, LOCATE('@', email) - 1) AS username FROM users;
注意:如果 email 不含 @,LOCATE 返回 0,此时 0 - 1 = -1,MySQL 会从倒数第 1 位开始截取(即最后一个字符),结果不可控。应加保护:
- 用
CASE WHEN LOCATE('@', email) > 0 THEN ... ELSE email END - 或用
IFNULL(NULLIF(LOCATE('@', email), 0), LENGTH(email)+1)避免负长度 - PostgreSQL 必须用
SUBSTRING(email FROM 1 FOR POSITION('@' IN email) - 1),且同样要判空
截取固定长度但避免越界报错
当字段内容可能短于预期长度时,直接写 SUBSTRING(title, 1, 20) 在多数数据库中不会报错,但结果可能比预期短 —— 这本身没问题;真正危险的是某些旧版 SQL Server(如 2005)在 len 为负数时抛异常,而更隐蔽的问题是:截取中文时,如果字段是 VARCHAR 但按字节计算(如 legacy latin1),SUBSTRING 可能切在 UTF-8 多字节中间,导致乱码(尤其导出到 Excel 或日志时)。
- 确保字段字符集为
utf8mb4(MySQL)或UTF8(PostgreSQL),SUBSTRING按字符而非字节操作 - SQL Server 若列是
NVARCHAR,则SUBSTRING天然按 Unicode 字符计数;若为VARCHAR且服务器排序规则非 UTF-8,慎用 - 安全写法:用
LEFT(title, 20)替代SUBSTRING(title, 1, 20),语义更清晰,且所有主流数据库都支持LEFT(SQL Server、MySQL 5.7+、PostgreSQL 13+)
用 SUBSTRING 实现模糊匹配前缀(比如查所有“张”姓用户)
这不是 SUBSTRING 的本职工作,但常被误用。有人写 WHERE SUBSTRING(name, 1, 1) = '张',性能极差——无法走索引(除非建函数索引)。正确做法永远优先用 name LIKE '张%'。
只有当你必须处理「第 N 位之后的内容」才值得用 SUBSTRING,例如清洗数据:
UPDATE logs SET path = SUBSTRING(path, 9) WHERE path LIKE '/api/v1%'; -- 去掉固定前缀
-
SUBSTRING(path, 9)省略第三参数,表示「从第 9 位到末尾」,各数据库均支持 - 如果
path长度不足 9,MySQL 返回空串,SQL Server 报错「Invalid length parameter」,PostgreSQL 返回空字符串 - 生产环境批量更新前,务必先
SELECT COUNT(*)验证LENGTH(path) >= 9的记录占比
最易被忽略的一点:SUBSTRING 的第三个参数(长度)为 NULL 时,MySQL 返回 NULL,SQL Server 直接报错,PostgreSQL 返回空字符串 —— 跨数据库迁移 SQL 时,这个细微差异常引发线上数据异常。










