SUBSTRING函数核心是从指定位置(1起始)按长度截取子串,参数顺序为(str, start, length),省略length时截取至末尾;不同数据库对负数start、越界处理等行为存在差异。

SUBSTRING 函数的基本用法和参数顺序必须搞清
SQL 中 SUBSTRING 的行为因数据库而异,但核心逻辑一致:从指定位置开始、按指定长度截取。最容易出错的是参数顺序和起始位置是否从 0 或 1 开始。
MySQL / PostgreSQL / SQL Server(兼容模式)都使用 SUBSTRING(str, start, length),其中 start 是**从 1 开始计数**的偏移量;而 SQLite 默认是 SUBSTRING(str, start, length),但底层也按 1 起始——这点常被误以为是 0 基。
- 写
SUBSTRING('hello', 0, 2)在 MySQL 中会返回空字符串(不是 'he'),因为 0 不合法 -
SUBSTRING('hello', 1, 2)→'he',SUBSTRING('hello', 2, 3)→'ell' - 省略
length参数时(如SUBSTRING(col, 5)),多数引擎会截取从第 5 位到末尾
从 URL 或日志字段中提取 query 参数值
典型场景:字段存着 'https://example.com/path?name=alice&age=30',想取 age 的值 '30'。不能硬写固定位置,得先定位 'age=',再向后跳过 4 位,再找下一个 '&' 或结尾。
以 MySQL 为例,组合 LOCATE 和 SUBSTRING:
SELECT
SUBSTRING(
url,
LOCATE('age=', url) + 4,
IFNULL(LOCATE('&', url, LOCATE('age=', url)) - LOCATE('age=', url) - 4, LENGTH(url))
) AS age_value
FROM logs;-
LOCATE('age=', url) + 4是跳过'age='四个字符后的起始位置 - 第二个
LOCATE带第三个参数,表示从某位置开始搜索'&',避免匹配到前面的 -
IFNULL(..., LENGTH(url))是为了兜底:如果'&'不存在(即age是最后一个参数),就截到末尾
处理 NULL 或不匹配时的空值风险
SUBSTRING 遇到 NULL 输入直接返回 NULL,但更隐蔽的问题是:当 start 超出字符串长度,或 LOCATE 找不到子串返回 0,会导致 SUBSTRING(col, 0, ...) 或 SUBSTRING(col, -1, ...) 等非法调用——不同数据库表现不一:MySQL 返回空,PostgreSQL 报错 ERROR: substring error: negative substring length。
- 务必用
CASE WHEN LOCATE(...) > 0 THEN SUBSTRING(...) ELSE NULL END包一层 - 在 WHERE 条件里提前过滤掉不含目标参数的行,比如
WHERE url LIKE '%age=%' - 对用户输入或日志类不可控字段,建议加
COALESCE(LOCATE(...), 0)防止运算中混入 NULL
替代方案:正则更稳,但要注意引擎支持
如果数据库支持正则(MySQL 8.0+、PostgreSQL、Oracle),用 REGEXP_SUBSTR 或 REGEXP_REPLACE 更可靠,比如提取 age= 后的数字:
-- MySQL 8.0+ SELECT REGEXP_SUBSTR(url, 'age=([0-9]+)', 1, 1, '', 1) AS age_value FROM logs;
- 最后的
1表示取第一个捕获组,即括号里的数字部分 - 比嵌套
LOCATE+SUBSTRING更易读、容错更强 - 但 SQLite 默认不支持正则函数(需加载扩展),SQL Server 直到 2022 版才原生支持
STRING_SPLIT类辅助,仍不直接支持REGEXP_SUBSTR
真正麻烦的不是语法怎么写,而是你得先确认当前数据库版本是否把 REGEXP_SUBSTR 当作可用函数暴露出来——查 INFORMATION_SCHEMA.ROUTINES 比翻文档更快。

















