substring函数参数顺序因数据库而异:mysql/postgresql为substring(str, start, length),sql server/oracle常用相同顺序;start从1开始,超长返回空串,负length在mysql报错、sql server返回空;处理unicode需确保utf8mb4字符集与正确collation;left/right更直观且跨库兼容;order by或where中滥用substring会导致索引失效,应改用like或添加生成列索引;关键场景建议先trim和正则清洗再截取。

SUBSTRING 函数的基本用法和参数顺序
SUBSTRING 在不同数据库里参数顺序不一致,这是最容易出错的地方。MySQL 和 PostgreSQL 用 SUBSTRING(str, start, length),而 SQL Server 和 Oracle 支持两种写法,但更常用的是 SUBSTRING(str, start, length);PostgreSQL 还支持 SUBSTR() 别名,行为一致。
注意:start 位置从 1 开始(不是 0),传入 0 或负数时,MySQL 会转为 1,SQL Server 则可能报错或返回空字符串。
- 想从第 3 个字符开始取 5 个字符:用
SUBSTRING(title, 3, 5) - start 超出字符串长度(比如
SUBSTRING('abc', 5, 2))→ 返回空字符串,不是报错 - length 为负数:MySQL 直接报错,SQL Server 会忽略负值并返回空字符串
处理中文、emoji 或多字节字符时的截断风险
SUBSTRING 按“字符数”计算,不是“字节数”,但前提是数据库字符集和排序规则(collation)正确识别 Unicode。如果字段是 utf8mb4 且 collation 是 utf8mb4_unicode_ci,那一个 emoji(如 ?)或中文汉字都算作 1 个字符,SUBSTRING(name, 1, 10) 就真截 10 个字。
但如果字段用了过时的 utf8(实际只支持 BMP 字符),或者 collation 是 utf8_general_ci,某些四字节 emoji 可能被截成乱码或丢失。
- 检查字段编码:
SHOW FULL COLUMNS FROM table_name LIKE 'column_name';看Collation列 - 安全做法:对用户输入或富文本字段,先用
CHAR_LENGTH()判断总长度,再决定是否截取 - 避免在 WHERE 条件里对大字段用
SUBSTRING(content, 1, 100) = 'xxx'—— 无法走索引
替代方案:LEFT / RIGHT 函数更直观
如果只是从开头或结尾固定长度截取,LEFT(str, n) 和 RIGHT(str, n) 更清晰、可读性高,且跨库兼容性更好(MySQL、SQL Server、PostgreSQL 都支持,Oracle 不支持需改用 SUBSTR)。
- 取前 8 个字符:
LEFT(description, 8)比SUBSTRING(description, 1, 8)少写两个参数 - 取后 4 个字符:
RIGHT(filename, 4),不用手动算起始位置 - 注意:
LEFT(NULL, 5)返回 NULL,不是空字符串;和SUBSTRING(NULL, 1, 5)行为一致
在 ORDER BY 或 GROUP BY 中使用 SUBSTRING 的性能陷阱
直接在排序或分组字段上套 SUBSTRING(如 ORDER BY SUBSTRING(email, LOCATE('@', email) + 1))会导致全表扫描,因为无法利用 email 字段上的索引。
如果这类操作频繁,应该考虑增加计算列(generated column)并建索引:
ALTER TABLE users ADD COLUMN domain VARCHAR(255)
GENERATED ALWAYS AS (SUBSTRING(email, LOCATE('@', email) + 1)) STORED;
然后对 domain 建索引:CREATE INDEX idx_domain ON users(domain);
- MySQL 5.7+、PostgreSQL 12+、SQL Server 2016+ 支持函数索引或生成列
- 别在 WHERE 中写
SUBSTRING(phone, 1, 3) = '138'查号段——改成phone LIKE '138%'才能走索引 - 如果必须用 SUBSTRING 做匹配,且数据量不大,加个注释说明“此处放弃索引,仅用于小表临时分析”反而更诚实
真正麻烦的不是语法记不住,而是当字段内容混着中英文、emoji、空格、不可见控制符时,SUBSTRING 截出来的结果看起来“差不多”,但下游系统解析失败——建议关键场景加一层 TRIM() 和 REGEXP_REPLACE() 清洗后再截取。











