常用字符串函数
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')→5locate('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 为例:
| 字符 | h | e | l | l | o | w | o | r | l | d |
|---|---|---|---|---|---|---|---|---|---|---|
| 正向下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
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 开始)
| 字符 | h | e | l | l | o | w | o | r | l | d |
|---|---|---|---|---|---|---|---|---|---|---|
| 反向下标 | -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. 今天的练习清单
-
lengthvschar_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能去掉字符串中间的空格。
小结
- 长度:
char_length数字数(字符个数),length数字节(与编码有关)。 upper/lower改大小写;trim去两端空白。locate找位置,0 = 没有;substring按下标截取。- 正向下标从 1,反向从 -1;函数可以嵌套。
- 下一篇学日期时间函数:年月日、第几天、生日类条件。
系列导航:总目录 · 上一篇:WHERE 与 LIKE · 下一篇:日期与时间函数