按分隔符切分字符串是什么
MySQL 的 SUBSTRING_INDEX 返回“某个分隔符第 n 次出现位置之前或之后”的整段内容;PostgreSQL 的 split_part 返回“按分隔符切开后的第 n 段”。两者名字相近但语义不同,混用是最常见的错误来源之一。
基本信息
| MySQL 语法 | SUBSTRING_INDEX(str, delim, count) |
|---|---|
| MySQL count 为正 | 取左侧 count 个分隔符范围内的内容(前 count 段拼起来) |
| MySQL count 为负 | 从右侧数,取最后 |count| 段 |
| MySQL 找不到分隔符 | 返回原字符串 |
| PostgreSQL | split_part(str, delim, n),n 从 1 开始 |
| PG 边界 | 段不存在时返回空字符串;14 起支持负索引 |
MySQL 写法
MySQL 写法
SELECT SUBSTRING_INDEX('a.b.c', '.', 2); -- 'a.b':前两段合起来
SELECT SUBSTRING_INDEX('a.b.c', '.', -1); -- 'c':最后一段
SELECT SUBSTRING_INDEX('a.b.c', '.', -2); -- 'b.c':最后两段
SELECT SUBSTRING_INDEX('abc', '.', 1); -- 'abc':没有分隔符就返回原串
-- 常用组合:从 host:port 里取出主机名
SELECT SUBSTRING_INDEX('api.example.com:8080', ':', 1) AS host;PostgreSQL 写法
PostgreSQL 写法
SELECT split_part('a.b.c', '.', 2); -- 'b':第 2 段
SELECT split_part('a.b.c', '.', 1); -- 'a'
SELECT split_part('a.b.c', '.', 4); -- '':段不存在返回空串
-- PostgreSQL 14 起支持负索引
SELECT split_part('a.b.c', '.', -1); -- 'c'两库语义对照
| 表达式 | MySQL 结果 | PostgreSQL 结果 |
|---|---|---|
| 取第 2 段 | SUBSTRING_INDEX('a.b.c','.',2) 得 'a.b' | split_part('a.b.c','.',2) 得 'b' |
| 取最后 1 段 | SUBSTRING_INDEX(…,-1) 得 'c' | split_part(…,-1) 得 'c'(14+) |
| 越界 | 返回原串或全部段 | 返回空字符串 |
| 无分隔符 | 返回原串 | n=1 返回原串,n>1 返回空串 |
| 多字符分隔符 | 支持 | 支持 |
典型使用场景
- 解析 IP 或路径:取最后一段或倒数第二段
- 从域名里去掉端口、从邮箱里取用户名
- 版本号拆分:分别取主版本号与次版本号
- 数据清洗:从带前缀的编号里取出纯数字部分
- 导入校验:检查字段是否按约定格式分段
- 日志解析:按固定分隔符取出第 n 个字段
- 号码解析:从带分隔符的编码里取出前几位作为分类依据
- 清洗埋点参数:把拼接字符串拆成可读的分段再做核对
两个函数的“第 n 段”语义不同:MySQL 返回的是“第 n 个分隔符之前(或之后)的整段”,PG 返回的是“切开后的第 n 段”。把 MySQL 的写法直接搬到 PG 会得到多段拼接的结果。
用逗号串存多值再拆分是最容易埋坑的设计:拆分后无法使用索引,也保证不了引用完整性。能用关系表就用关系表,确实需要半结构化存储时优先用 JSON 数组列。