SUBSTRING 是什么
SUBSTRING 按位置截取子串,是字符串清洗与编码解析的常用工具。MySQL 支持 SUBSTRING(str, pos, len),pos 为负数时从末尾往前数,另有 LEFT 与 RIGHT 做定长截取;PostgreSQL 既支持 substring(str from start for count) 这种标准写法,也支持 substr(str, start, count) 函数写法。两库的截取都按字符计数而不是字节,UTF-8 下中文不会被截成半个字符,但与按字节返回长度的函数混用时要注意口径。
基本信息
| MySQL 写法 | SUBSTRING(str, pos) 与 SUBSTRING(str, pos, len) |
|---|---|
| MySQL 负数位置 | pos 为负表示从字符串末尾往前数 |
| PostgreSQL 写法 | substring(str from 2 for 3) 或 substr(str, 2, 3) |
| 定长截取 | LEFT(str, n) 与 RIGHT(str, n) |
| 计数单位 | 按字符计数,UTF-8 下中文不会被截断 |
| 索引影响 | 对列做截取后再比较,普通索引无法用于该列 |
典型使用场景
- 提取固定位编码:从订单号里截出渠道与日期段
- 脱敏展示:手机号只显示前三位与后四位
- 按前缀分组:用截取结果当分组维度
- 清洗脏数据:去掉前后多余内容再入库
- 拆分拼接字段:把用分隔符拼在一起的字段拆开
- 长度规整:把超长文本截到目标列可以接受的长度
示例
示例
-- MySQL
SELECT SUBSTRING('ORDER202405010001', 1, 5) AS prefix, # ORDER
SUBSTRING('ORDER202405010001', 6, 8) AS day_part, # 日期段
SUBSTRING('ORDER202405010001', -4) AS tail, # 末尾四位
LEFT('ORDER202405010001', 5) AS head; # 定长左截
-- PostgreSQL
SELECT substring('ORDER202405010001' from 1 for 5) AS prefix,
substr('ORDER202405010001', -4) AS tail,
left('ORDER202405010001', 5) AS head;
-- 脱敏示例:只保留前三位与后四位
SELECT CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) FROM users;截取写法对照
| 需求 | MySQL | PostgreSQL |
|---|---|---|
| 从第 2 位取 3 个字符 | SUBSTRING(s, 2, 3) | substring(s from 2 for 3) |
| 末尾四位 | SUBSTRING(s, -4) 或 RIGHT(s, 4) | right(s, 4) |
| 前五位 | LEFT(s, 5) | left(s, 5) |
| 长度 | CHAR_LENGTH(s) | char_length(s) |
| 字节长度 | LENGTH(s) | octet_length(s) |
MySQL 的 LENGTH 返回字节数,CHAR_LENGTH 返回字符数;中文在 UTF-8 下占三个字节,用错函数会让长度判断差好几倍。
在 WHERE 里对列使用 SUBSTRING 会让该列的普通索引失效,条件能改写为前缀比较(LIKE 'abc%')时优先用前缀形式。
位置从 1 开始计数,不是 0;从 0 开始写不会报错但结果与预期不同,迁移脚本里要特别核对。
使用要点
- 先确认位置基准:SQL 里下标从 1 开始
- 定长截取优先用 LEFT 与 RIGHT,意图更清楚
- 按字符计数,避免用字节长度做长度校验
- 截取结果参与比较时考虑加冗余列或函数索引
- 脱敏逻辑放在接口层或视图,原表保留完整数据
- 处理空串与 NULL:先兜底再截取,避免整列变 NULL