MySQL

常用字符串函数

MySQL 字符串函数:length/char_length、upper/lower、trim、locate 查找、substring 截取(正向与反向下标)及函数嵌套。

查询不只会「筛行」,还要加工文字:数长度、转大小写、去空格、查关键词、截取子串。今天练 MySQL 里最常用的字符串函数。

系列:MySQL 入门到查询 · 第 9 / 17 篇(第 9 天 · 4 月 29 日)
上一篇:WHERE 与 LIKE
下一篇:日期与时间函数
总目录:系列索引

环境说明

  • 库: rain(use train;)
  • 本篇大量使用 select 函数(...); 不依赖表 也能练
  • 若要对表练习,可用:
use train;

drop table if exists stu;
create table stu(
    id int,
    name varchar(20),
    phone varchar(11)
);

insert into stu(id, name, phone) values
    (1, 'zhangsan', '13800001234'),
    (2, '张三', '13900005678'),
    (3, '李三丰', '13700009999'),
    (4, '王五', '13611112222');

练习数据以本篇 seed 为准。

1. 函数是什么(一句话)

select  函数名(参数...);

函数像「小工具」:把文字/数字放进去,吐出一个结果。可以单独用,也可以写在 select 列表或 where 里。

select length('hello');

2. 数长度:length 与 char_length

函数数什么
length(...)字节数
char_length(...)字符个数(文字个数)
select length('helloworld');
select char_length('helloworld');
10
10

中文举例:

select char_length('hello中国');
7

h e l l o 中 国 → 7 个字符。

字节数为什么会「对不上」

select length('中国');

结果可能是 4 或 6,取决于:

情况常见结果
数据来自 utf8mb4 表列中文常 3 字节/字 → 「中国」约 6 字节
数据来自 字面量 且客户端/终端是 gbk中文常 2 字节/字 → 「中国」4 字节
-- 表内列(utf8mb4)
select name, length(name), char_length(name) from stu;

入门结论:

  • 想知道「几个字」→ 用 char_length
  • 想知道「占多少存储字节」→ 用 length,并注意编码
select name, phone, char_length(phone) from stu;

3. 转大小写

select upper('HelloWorld');
select lower('HelloWorld');
HELLOWORLD
helloworld
函数作用
upper转大写
lower转小写

4. 去空白:trim / ltrim / rtrim

select trim('  hello  world  ');
select ltrim('  hello  world  ');  -- 去左边
select rtrim('  hello  world  ');  -- 去右边

终端里肉眼难分辨是否去掉了空格,可以嵌套 char_length 观察:

select char_length('  hello  world  ');
select char_length(trim('  hello  world  '));
表达式含义(约)
原串16 个字符(含两侧空格)
trim 后去掉左右空格

注意:trim / ltrim / rtrim 不去掉中间空格。中间空格以后可用 replace 等函数处理。

select char_length(trim('  hello  world  '));
-- hello  world 仍保留中间两个空格

5. 查找位置:locate

select locate('o', 'helloworld');
select locate('o', 'helloworld', 1);
select locate('ll', 'helloworld');   -- 子串 ll 从第 3 个字符开始

语法:

locate(要找的内容, 原始字符串, 起始下标)
参数说明
第 1 个找什么
第 2 个在谁里面找
第 3 个从第几个位置开始找(默认从开头;从开头找时可省略)

helloworld 中:

h e l l o w o r l d
1 2 3 4 5 6 7 8 9 10
  • 第一个 o 在 5
  • locate('o','helloworld') → 5
  • locate('ll','helloworld') → 3(子串 ll 从第 3 个字符开始)
  • locate('low','helloworld') → 0(helloworld 里没有 low 这个子串)

找不到时返回 0

select locate('abc', 'helloworld');
0

0 表示没找到,不是报错。

找第二个 o

-- 从第一个 o 的下一位(6)开始
select locate('o', 'helloworld', 6);

-- 用嵌套:第一次位置 + 1
select locate('o', 'helloworld', locate('o', 'helloworld') + 1);

locate 放进 WHERE(是否包含)

select * from stu where locate('三', name) > 0;   -- 名字里含「三」
select * from stu where locate('三', name) = 0;   -- 不含「三」
返回值含义
> 0包含要找的内容
= 0不包含

和 like '%三%' 目的类似,写法不同;面试/课堂都常见 locate。

6. 截取:substring

substring(原始字符串, 起始下标, 截取个数)

6.1 正向下标(从左往右,从 1 开始)

以 helloworld 为例:

字符helloworld
正向下标12345678910
select substring('helloworld', 1, 2);  -- he
select substring('helloworld', 4, 3);  -- llo(第4、5、6个字符:l、l、o)
select substring('helloworld', 6, 5);  -- world
select substring('helloworld', 6);     -- world(省略个数 = 到末尾)
调用结果
(s, 1, 2)从第 1 个字符起,取 2 个 → he
(s, 4, 3)从第 4 个字符起,取 3 个 → llo
(s, 6)从第 6 个起到末尾 → world

注意:helloworld 第 4~6 个字符是 l、l、o,得到的是 llo,不是 low。

6.2 反向下标(从右往左,从 -1 开始)

字符helloworld
反向下标-10-9-8-7-6-5-4-3-2-1
select substring('helloworld', -2);  -- ld(从倒数第 2 个起到末尾)
场景建议
截左边一段用正向下标更直观
截右边末尾几位用反向下标更省事

注意:不是所有函数都支持反向下标;locate 的起始位置用的是从左数的正向习惯。入门以 substring 练反向即可。

6.3 在表里截取姓名、手机号

-- 姓:第 1 个字
select name, substring(name, 1, 1) from stu;

-- 名:第 2 个字起到末尾(两字名/三字名都适用这一种粗切法)
select name, substring(name, 2) from stu;

-- 手机号前 3 位(号段示意)
select name, substring(phone, 1, 3) from stu;

-- 手机号最后 4 位
select name, substring(phone, -4) from stu;

复姓(如「欧阳」)用 substring(name,1,1) 取姓不完整——课堂常先忽略,生产要另设计姓名字段。

7. 函数嵌套:小工具叠着用

函数的返回值可以再交给另一个函数:

select char_length(trim('  hello  world  '));

顺序:先 trim,再 char_length。

select substring(trim('  hello  '), 1, 5);
select locate('o', 'helloworld', locate('o', 'helloworld') + 1);

读法:里面的 locate(...) 先算出第一次出现位置,+1 后作为外层的起始下标。

8. 综合小案例

-- 手机号是否 11 位
select name, phone, char_length(phone) from stu
where char_length(phone) = 11;

-- 名字里含「三」
select * from stu where locate('三', name) > 0;

-- 显示「姓 + 手机后四位」
select substring(name,1,1) as 姓, substring(phone,-4) as 后四位
from stu;

「固定 3 个字的省 + 市」这类地址拆分,因各省名称长度不同,不能用死下标;要靠更规范的表设计或复杂函数嵌套(见课堂进阶)。入门先掌握固定长度场景。

9. 完整跟练脚本

-- 不依赖表
select length('helloworld');
select char_length('hello中国');
select upper('HelloWorld');
select lower('HelloWorld');
select char_length('  hello  world  ');
select char_length(trim('  hello  world  '));
select locate('o','helloworld');
select locate('ll','helloworld');
select locate('low','helloworld');
select locate('o','helloworld',6);
select substring('helloworld',1,2);
select substring('helloworld',4,3);
select substring('helloworld',6);
select substring('helloworld',-2);

-- 表练习
use train;
drop table if exists stu;
create table stu(id int, name varchar(20), phone varchar(11));
insert into stu values
    (1,'zhangsan','13800001234'),
    (2,'张三','13900005678'),
    (3,'李三丰','13700009999'),
    (4,'王五','13611112222');

select name, length(name), char_length(name) from stu;
select name, phone, char_length(phone) from stu;
select * from stu where locate('三', name) > 0;
select substring(name,1,1), substring(phone,-4) from stu;

10. 速查表

目标函数
字节数length(str)
字符个数char_length(str)
转大写 / 小写upper / lower
去两端空白trim / ltrim / rtrim
查找位置locate(子串, 原串[, 起始])
没找到返回 0
截取substring(原串, 起始[, 个数])
省略个数截到末尾
反向截取substring(s, -n)
嵌套char_length(trim(s)) 等

11. 今天的练习清单

  • length vs char_length 对比 hello 与 hello中国
  • upper / lower 各一句
  • 用 char_length(trim(...)) 观察去空格
  • locate('o','helloworld') 与 locate('low','helloworld')(后者应为 0)
  • 用嵌套找第二个 o
  • substring('helloworld',4,3) 得到 llo
  • substring(phone,-4) 取手机后四位
  • where locate('三',name)>0 筛选 stu

常见错误

易错:分不清 length(字节)和 char_length(字符)。中文场景优先想清楚要哪个。
易错:locate 的起始下标从 1 开始;找不到返回 0,条件写 =0 表示不含。
易错:substring 起始是 1 不是 0(正向)。
易错:反向下标从 -1 开始;-2 表示倒数第 2 个字符起。
易错:省略 substring 第三个参数时,是「截到结尾」,不是「截 1 个」。
易错:以为 trim 能去掉字符串中间的空格。

小结

  1. 长度:char_length 数字数(字符个数),length 数字节(与编码有关)。
  2. upper/lower 改大小写;trim 去两端空白。
  3. locate 找位置,0 = 没有;substring 按下标截取。
  4. 正向下标从 1,反向从 -1;函数可以嵌套。
  5. 下一篇学日期时间函数:年月日、第几天、生日类条件。

系列导航:总目录 · 上一篇:WHERE 与 LIKE · 下一篇:日期与时间函数

相关阅读

全部文章 →
← 返回列表更多「MySQL」