SUBSTRING函数在主流数据库中起始位置均为1-based,但函数名、参数语法及异常处理差异大:MySQL/PostgreSQL/SQL Server用SUBSTRING(str,start,len),Oracle用SUBSTR;start=0时MySQL返回空、PostgreSQL报错、SQL Server自动修正为1。

SUBSTRING 在大多数 SQL 方言中能截取字符串,但参数顺序和起始位置是否从 0 或 1 开始,各数据库差异极大——直接照搬 MySQL 写法在 PostgreSQL 或 SQL Server 上大概率报错。
SUBSTRING 参数顺序和起始索引差异
不同数据库对 SUBSTRING(str, start, length) 的解释不一致:
- MySQL、PostgreSQL、SQLite:起始位置从
1开始,SUBSTRING('hello', 2, 3)返回'ell' - SQL Server:支持两种语法——
SUBSTRING(str, start, length)(起始为1),也支持LEFT/RIGHT等替代方案 - Oracle:用
SUBSTR(str, start, length),同样从1开始;但若start为负数,表示从末尾倒数(如-2表示倒数第 2 个字符) - 注意:
start = 0在 MySQL 中等价于1,但在 PostgreSQL 中会返回空字符串或报错(取决于版本)
截取固定长度子串的常见写法
想取前 5 个字符?别硬记函数,先看数据库类型再选写法:
- MySQL / PostgreSQL / SQLite:
SUBSTRING(column_name, 1, 5) - SQL Server:
SUBSTRING(column_name, 1, 5)或更简洁的LEFT(column_name, 5) - Oracle:
SUBSTR(column_name, 1, 5) - 如果字段可能为
NULL,所有方言中SUBSTRING(NULL, ...)都返回NULL,无需额外判断——但若依赖结果做连接或过滤,得提前COALESCE
从某字符后截取(比如取邮箱 @ 后域名)
这需要组合 POSITION(或 CHARINDEX)、LENGTH 和 SUBSTRING,且各库函数名不同:
- PostgreSQL:
SUBSTRING(email FROM POSITION('@' IN email) + 1) - MySQL:
SUBSTRING(email, LOCATE('@', email) + 1) - SQL Server:
SUBSTRING(email, CHARINDEX('@', email) + 1, LEN(email)) - Oracle:
SUBSTR(email, INSTR(email, '@') + 1) - 关键点:
LOCATE/POSITION/CHARINDEX/INSTR返回位置都是从1开始,所以加1才跳过@本身 - 如果字段不含
@,MySQL 和 Oracle 返回0,导致截取从位置1开始(整字段);PostgreSQL 和 SQL Server 会返回NULL或报错——务必加CASE WHEN判断
性能与可读性提醒
在 WHERE 条件中对字段用 SUBSTRING(如 WHERE SUBSTRING(name, 1, 3) = 'abc')通常无法走索引,尤其当 SUBSTRING 出现在左侧时。更高效的做法是:
- 用前缀匹配:
WHERE name LIKE 'abc%'(可利用 B-tree 索引) - 对高频截取场景,建生成列(MySQL 5.7+、PostgreSQL 12+)或计算列(SQL Server)并为其建索引
-
SUBSTRING是标量函数,嵌套太深(如多层SUBSTRING(SUBSTRING(...)))会让执行计划变复杂,也难调试——拆成 CTE 或子查询更清晰
最常被忽略的是:跨数据库迁移 SQL 时,SUBSTRING 的起始索引行为差异会导致数据截断错误,而不是语法报错——结果错得安静又难发现。

















