SUBSTRING函数基本用法为SUBSTRING(str, start, length),起始位置从1开始;MySQL/PostgreSQL用SUBSTRING(str, pos, len),SQL Server/Oracle用SUBSTRING(str, start, length)或SUBSTR(str, start, len),各库对NULL、越界和分隔符定位处理存在差异。

SUBSTRING函数的基本用法和参数顺序
SUBSTRING 函数在不同数据库里参数顺序不一致,这是最容易出错的地方。MySQL 和 PostgreSQL 用 SUBSTRING(str, pos, len),而 SQL Server 和 Oracle 支持 SUBSTRING(str, start, length),但 Oracle 还额外支持 SUBSTR()(注意少一个 T),且参数顺序一样。PostgreSQL 同时兼容 SUBSTR() 形式。
关键点:起始位置从 1 开始(不是 0),这点和多数编程语言相反;如果 len 超出剩余长度,自动截到末尾,不会报错。
- MySQL 示例:
SUBSTRING('hello world', 7, 5)→'world' - SQL Server 示例:
SUBSTRING('hello world', 7, 5)→ 同样返回'world' - Oracle 示例:
SUBSTR('hello world', 7, 5)→ 结果一致
处理 NULL 或空字符串时的隐性陷阱
如果被截取字段是 NULL,所有主流数据库都返回 NULL,而不是空字符串。这会导致后续拼接或比较逻辑意外中断,比如 WHERE SUBSTRING(name, 1, 2) = 'Li' 会跳过所有 name 为 NULL 的行,但你可能没意识到它根本没参与匹配。
- 安全写法:显式过滤或补默认值,例如
SUBSTRING(COALESCE(name, ''), 1, 2) - 避免直接对可能为 NULL 的字段调用
SUBSTRING后做等值判断 - 注意空字符串
''是合法输入,SUBSTRING('', 1, 10)返回'',不是NULL
用 SUBSTRING 提取固定分隔符后的部分(如邮箱域名)
想从 user@example.com 中提取 example.com,不能硬写起始位置,得先定位 @。这时候要嵌套 CHARINDEX(SQL Server)、LOCATE(MySQL)或 POSITION(PostgreSQL)。
MySQL 写法:SUBSTRING(email, LOCATE('@', email) + 1)
SQL Server 写法:SUBSTRING(email, CHARINDEX('@', email) + 1, LEN(email))
PostgreSQL 写法:SUBSTRING(email FROM POSITION('@' IN email) + 1)
- MySQL/PostgreSQL 的
LOCATE/POSITION找不到时返回 0,加 1 后变成从位置 1 开始,结果可能不对——务必加WHERE email LIKE '%@%'预过滤 - SQL Server 的
CHARINDEX找不到时返回 0,SUBSTRING(..., 0+1, ...)会从第 1 位开始,也容易误取全量 - 长度参数传
LEN()或LENGTH()不必要,省略第三个参数即可取到末尾
性能影响:SUBSTRING 能否走索引?
绝大多数情况下,SUBSTRING(col, 1, N) 或 SUBSTRING(col, N, M) 都无法利用 col 上的标准 B-tree 索引,因为数据库无法预知截取后值的有序性。只有极少数场景能命中索引,比如 MySQL 8.0+ 对函数索引的支持:
你可以建函数索引:CREATE INDEX idx_email_domain ON users (SUBSTRING(email, LOCATE('@', email) + 1)),但要注意该索引只对这个特定表达式有效,且维护成本略高。
- 日常查询中,优先考虑在应用层拆分存储(如单独存 domain 字段),比反复计算更可靠
- 如果必须用
SUBSTRING做 WHERE 条件,确认执行计划是否出现Index Scan而非Seq Scan或Table Scan - 在 WHERE 子句里对字段用
SUBSTRING,基本等于放弃索引——除非你用了函数索引并确保查询条件完全匹配索引表达式


















