substring(col, 6) 是从第6位开始取至末尾以跳过前5字符,非截掉前n位;各数据库起始位置均从1计数,省略长度参数时自动截到末尾最安全。

直接说结论:SUBSTRING 不是用来“截掉前 N 位”的函数,而是“从第 N 位开始取”的函数;想跳过前 5 个字符,必须写 SUBSTRING(col, 6),不是 SUBSTRING(col, 1, 5)——后者是取前 5 位,完全反了。
为什么 SUBSTRING(col, 6) 能截掉前 5 位?
因为 SUBSTRING 的第二个参数是起始位置,且所有主流数据库(MySQL、PostgreSQL、SQL Server、Oracle)都从 1 开始计数,不是 0。所以第 6 位就是第 1 位之后的第 5 个字符之后的位置。
-
SUBSTRING('abcde12345', 1)→ 'abcde12345'(从头开始) -
SUBSTRING('abcde12345', 6)→ '12345'(跳过前 5 个) -
SUBSTRING('abc', 6)→NULL(起始位置超出长度,不报错但返回空值)
省略第三个参数(长度)时,数据库自动截到末尾,这是最常用也最安全的写法。
不同数据库对 SUBSTRING 的兼容写法
函数名和语法看似统一,但细节差异极易导致迁移出错:
- MySQL / PostgreSQL:
SUBSTRING(col, 6)或标准 SQL 写法SUBSTRING(col FROM 6) - SQL Server:
SUBSTRING(col, 6, 2147483647)—— 推荐用最大 int 值代替LEN(col),避免LEN(NULL)导致整个表达式为NULL - Oracle:
SUBSTR(col, 6)更常用;SUBSTRING需开启兼容模式,不建议依赖 - SQLite:支持
SUBSTR()和SUBSTRING(),行为一致
别硬记“SUBSTRING 到处都能用”,实际项目里看到 SUBSTR 才该放心。
如何避免 NULL 或长度不足导致静默失败?
直接写 SUBSTRING(col, 6) 在字段为空或短于 6 位时会返回 NULL,而这个 NULL 很可能被上层应用忽略,造成数据丢失却无提示。
- MySQL:
IF(CHAR_LENGTH(col) >= 6, SUBSTRING(col, 6), '') - PostgreSQL:
CASE WHEN LENGTH(col) >= 6 THEN SUBSTRING(col FROM 6) ELSE '' END - SQL Server:
IIF(LEN(col) >= 6, SUBSTRING(col, 6, 2147483647), '')
注意:COALESCE(SUBSTRING(col, 6), '') 不解决问题——它只是把 NULL 变成空字符串,无法区分“原字段太短”和“原字段就是 NULL”。必须提前判断长度。
SUBSTRING 与 LEFT/RIGHT 的分工边界
很多人试图用 SUBSTRING 做左右截取,其实大可不必:
- 取前 N 位,用
LEFT(col, N)—— 语义清晰、跨库兼容好、性能略优 - 取后 N 位,用
RIGHT(col, N)—— 同样直观,且避免手动算起始位置(比如SUBSTRING(col, LEN(col)-N+1)容易错) - 只有需要“从中间某位置开始一直取到结尾”或“基于动态位置(如
CHARINDEX('@', email)+1)截取”时,才真正需要SUBSTRING
硬用 SUBSTRING 替代 LEFT 或 RIGHT,既增加理解成本,又引入额外出错点。
真正麻烦的从来不是函数怎么写,而是你不知道字段里混着空值、超短字符串、甚至全是空格——这些边界情况不会报错,只会悄悄让结果变成 NULL 或空字符串,等报表跑出来才发现数据断层。











