MySQL中的字符串函数
目录
一、字符串【分割】函数:SUBSTRING_INDEX()
SUBSTRING_INDEX函数
练习题
统计每种性别的人数
提取博客URL中的用户名
截取出年龄
SQL83 商品id数据清洗统计
SQL250 查找字符串中逗号出现的次数
二、字符串【截取】函数:SUBSTRING()
基本语法
参数说明
使用示例
示例数据
示例1:从指定位置开始截取
示例2:指定截取长度
示例3:从字符串末尾开始截取(使用负数位置)
示例4:结合其他字符串函数使用
示例5:处理可能不存在的分隔符
注意事项
三、正则表达式函数:REGEXP_SUBSTR()
1、基本语法
2、参数说明
3、核心功能
4、使用示例
示例数据
示例1:基本提取
示例2:指定匹配项序号
示例3:邮箱提取
示例4:使用捕获组
示例5:IP地址提取
5、匹配修饰符(match_type)
6、特殊注意事项
7、与类似函数对比
四、JSON函数
1、创建JSON值
2、查询JSON值
3、修改JSON值
4、JSON路径表达式
5、其他实用函数
6、实际应用示例
五、字符串搜索和位置定位:LOCATE()
基本语法
参数说明
返回值
使用示例
示例数据
示例1:基本查找
示例2:指定起始位置
示例3:与SUBSTRING结合使用
示例4:处理找不到的情况
示例5:INSTR函数(参数顺序不同)
注意事项
一、字符串【分割】函数:SUBSTRING_INDEX()
MySQL本身没有内置的SPLIT()
函数,但可以通过其他方式实现字符串分割功能。
SUBSTRING_INDEX函数
SUBSTRING_INDEX()
是MySQL中最常用的字符串分割函数,它可以根据指定的分隔符从字符串中提取子串,语法如下:
SUBSTRING_INDEX(str, delim, count)
含义
:返回字符串 str 中按分隔符 delim 分割后的第 count 个子串。str
: 要分割的字符串delim
: 分隔符(可以是单个字符或多个字符)count
:- 正数:返回从左边开始第count个分隔符之前的所有内容
- 负数:返回从右边开始第count个分隔符之后的所有内容
1、基本用法
-- 获取第一个逗号前的内容
SELECT SUBSTRING_INDEX('apple,banana,orange', ',', 1);
-- 结果: 'apple'-- 获取最后一个逗号后的内容
SELECT SUBSTRING_INDEX('apple,banana,orange', ',', -1);
-- 结果: 'orange'-- 获取前两个元素
SELECT SUBSTRING_INDEX('apple,banana,orange', ',', 1) AS item1,SUBSTRING_INDEX(SUBSTRING_INDEX('apple,banana,orange', ',', 2), ',', -1) AS item2;
-- 结果: item1='apple', item2='banana'
2. 处理多字符分隔符
-- 使用多字符作为分隔符
SELECT SUBSTRING_INDEX('apple||banana||orange', '||', 2);
-- 结果: 'apple||banana'SELECT SUBSTRING_INDEX('apple||banana||orange', '||', -1);
-- 结果: 'orange'
- 找到第一个 || 在 apple||banana||orange 的 apple 之后,此时已找到1次分隔符
- 找到第二个 || 在 banana 之后,此时已找到2次分隔符(达到count值)
- 函数返回从开头到第二个 || 之前的所有内容:‘apple||banana’
3. 边界情况处理
-- 分隔符不存在时返回原字符串
SELECT SUBSTRING_INDEX('apple_banana_orange', ',', 1);
-- 结果: 'apple_banana_orange'-- count超过实际分隔数时返回整个字符串
SELECT SUBSTRING_INDEX('apple,banana', ',', 5);
-- 结果: 'apple,banana'-- 空字符串处理
SELECT SUBSTRING_INDEX('', ',', 1);
-- 结果: ''
注意:对于复杂的字符串分割需求,建议在应用层处理(如Python、Java等),或者在数据库设计时就避免使用分隔符存储多个值(遵循第一范式!!!!!!!!!!!!!)。
练习题
统计每种性别的人数
selectSUBSTRING_INDEX (profile, ',', -1) as gender,count(*) as number
fromuser_submit
group bygender
提取博客URL中的用户名
selectdevice_id,substring_index (blog_url, "/", -1) as user_name
fromuser_submit
截取出年龄
selectsubstring_index (substring_index (profile, ",", 3), ",", -1) as age,count(*) as number
fromuser_submit
group byage
SQL83 商品id数据清洗统计
select# SUBSTRING_INDEX (order_id, '_', -1) as product_id,regexp_substr(order_id,'p[0-9]+$') as product_id,count(*) as cnt
from order_log
group by product_id
order by cnt desc,product_id asc;
- ‘p[0-9]+$’: 正则表达式模式
- p: 匹配字母 “p”
- [0-9]+: 匹配一个或多个数字(0-9)
- $: 匹配字符串的结尾
SQL250 查找字符串中逗号出现的次数
SELECTid,LENGTH(string) - LENGTH(REPLACE(string, ',', '')) AS cnt
FROMstrings;
核心思路:
1.计算原始字符串的长度
2.计算去掉所有逗号后的字符串长度
3.两者相减就是逗号的数量
因为每个逗号占一个字符长度,去掉一个逗号会使字符串长度减少1,所以差值就是逗号的数量。
二、字符串【截取】函数:SUBSTRING()
参考: SQL中字符串截取函数(SUBSTRING)
SUBSTRING()
是 MySQL 中用于截取字符串的函数(SUBSTR()
是其别名,功能完全相同)。
基本语法
SUBSTRING(string, start [, length])
SUBSTR(string, start [, length])
参数说明
- string:要截取的原始字符串(可以是字段名或字符串字面量)
- start:开始截取的位置(整数)
- 如果为正数,表示从字符串左侧开始计算的位置(从1开始)
- 如果为负数,表示从字符串右侧开始计算的位置(从-1开始)
- length(可选):要截取的字符数。如果省略,则截取从开始位置到字符串末尾的所有字符
使用示例
示例数据
假设有一个表 users
包含以下数据:
CREATE TABLE users (id INT,username VARCHAR(50)
);INSERT INTO users VALUES
(1, 'john_doe'),
(2, 'jane_smith'),
(3, 'bob123');
示例1:从指定位置开始截取
-- 从第3个字符开始截取(包含第3个字符)
SELECT username, SUBSTRING(username, 3) FROM users;
结果:
john_doe => hn_doe
jane_smith => ne_smith
bob123 => b123
示例2:指定截取长度
-- 从第2个字符开始截取3个字符
SELECT username, SUBSTRING(username, 2, 3) FROM users;
结果:
john_doe => ohn
jane_smith => ane
bob123 => ob1
示例3:从字符串末尾开始截取(使用负数位置)
-- 从倒数第3个字符开始截取
SELECT username, SUBSTRING(username, -3) FROM users;
结果:
john_doe => doe
jane_smith => ith
bob123 => 123
示例4:结合其他字符串函数使用
-- 提取电子邮件域名(从@符号后开始截取)
SELECT email, SUBSTRING(email, LOCATE('@', email) + 1) AS domain
FROM customers;
LOCATE()后文有介绍
示例5:处理可能不存在的分隔符
-- 安全提取域名,当没有@符号时返回NULL
SELECT email, CASE WHEN LOCATE('@', email) > 0 THEN SUBSTRING(email, LOCATE('@', email) + 1)ELSE NULLEND AS domain
FROM customers;
注意事项
- 如果
start
为0,MySQL 5.6+ 会返回空字符串,而早期版本可能返回整个字符串 - 如果
start
超出字符串长度,返回空字符串 - 如果
length
为负数,会被视为0,返回空字符串 - 对于多字节字符(如中文),每个字符仍计为1个位置
三、正则表达式函数:REGEXP_SUBSTR()
REGEXP_SUBSTR()
是 MySQL 中用于通过正则表达式提取子字符串的强大函数(MySQL 8.0+ 版本支持)。
1、基本语法
REGEXP_SUBSTR(string, pattern [, position [, occurrence [, match_type]]])
2、参数说明
参数 | 说明 |
---|---|
string | 要搜索的原始字符串 |
pattern | 正则表达式模式 |
position (可选) | 开始搜索的位置(默认1) |
occurrence (可选) | 要返回的匹配项序号(默认1) |
match_type (可选) | 匹配修饰符(如'i'忽略大小写) |
3、核心功能
从字符串中提取第一个匹配正则表达式的子字符串(除非指定occurrence)
4、使用示例
示例数据
CREATE TABLE sample_texts (id INT AUTO_INCREMENT PRIMARY KEY,content TEXT
);INSERT INTO sample_texts (content) VALUES
('联系电话:010-12345678,备用:020-87654321'),
('邮箱:user@example.com 和 admin@test.org'),
('订单号:ORD20230515-1234 总价:$299.99'),
('IPv4地址:192.168.1.1,MAC地址:00:1A:2B:3C:4D:5E');
示例1:基本提取
-- 提取第一个电话号码
SELECT content,REGEXP_SUBSTR(content, '[0-9]{3,4}-[0-9]{7,8}') AS phone
FROM sample_texts
WHERE id = 1;
结果:
+-----------------------------------------------+--------------+
| content | phone |
+-----------------------------------------------+--------------+
| 联系电话:010-12345678,备用:020-87654321 | 010-12345678 |
+-----------------------------------------------+--------------+
示例2:指定匹配项序号
-- 提取第二个电话号码
SELECT content,REGEXP_SUBSTR(content, '[0-9]{3,4}-[0-9]{7,8}', 1, 2) AS backup_phone
FROM sample_texts
WHERE id = 1;
结果:
+-----------------------------------------------+--------------+
| content | backup_phone |
+-----------------------------------------------+--------------+
| 联系电话:010-12345678,备用:020-87654321 | 020-87654321 |
+-----------------------------------------------+--------------+
示例3:邮箱提取
-- 提取所有邮箱地址
SELECT id,REGEXP_SUBSTR(content, '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}') AS email
FROM sample_texts
WHERE content REGEXP '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}';
结果:
+----+-------------------+
| id | email |
+----+-------------------+
| 2 | user@example.com |
| 2 | admin@test.org |
+----+-------------------+
示例4:使用捕获组
-- 提取订单号中的日期部分
SELECT content,REGEXP_SUBSTR(content, 'ORD([0-9]{8})', 1, 1, '', 1) AS order_date
FROM sample_texts
WHERE id = 3;
结果:
+---------------------------------------+------------+
| content | order_date |
+---------------------------------------+------------+
| 订单号:ORD20230515-1234 总价:$299.99 | 20230515 |
+---------------------------------------+------------+
示例5:IP地址提取
-- 提取IP地址的第三个八位组
SELECT content,REGEXP_SUBSTR(content, '([0-9]{1,3}\\.){2}([0-9]{1,3})', 1, 1, '', 2) AS ip_third_octet
FROM sample_texts
WHERE id = 4;
结果:
+-------------------------------------------------+---------------+
| content | ip_third_octet|
+-------------------------------------------------+---------------+
| IPv4地址:192.168.1.1,MAC地址:00:1A:2B:3C:4D:5E | 1 |
+-------------------------------------------------+---------------+
5、匹配修饰符(match_type)
修饰符 | 作用 |
---|---|
i | 不区分大小写 |
c | 区分大小写 |
m | 多行模式 |
n | 允许. 匹配换行符 |
u | Unix换行符 |
示例:
-- 不区分大小写匹配
SELECT REGEXP_SUBSTR('Hello World', 'woRLd', 1, 1, 'i') AS match_result;
-- 返回 'World'
6、特殊注意事项
- 性能影响:复杂正则表达式可能影响查询性能
- 版本要求:MySQL 8.0+ 完整支持
- 字符编码:确保正则表达式与字符串编码兼容
- 转义处理:在SQL字符串中需要双重转义(
\\d
表示\d
)
7、与类似函数对比
函数 | 特点 |
---|---|
SUBSTRING() | 简单位置截取 |
LOCATE() | 子字符串位置查找 |
REGEXP_SUBSTR() | 基于正则的灵活提取 |
REGEXP_REPLACE() | 正则替换 |
四、JSON函数
MySQL 从5.7版本开始支持JSON数据类型,并提供了一系列强大的JSON处理函数。
1、创建JSON值
-
JSON_OBJECT() - 创建JSON对象
SELECT JSON_OBJECT('name', '张三', 'age', 25, 'is_student', TRUE); -- 结果: {"name": "张三", "age": 25, "is_student": true}
-
JSON_ARRAY() - 创建JSON数组
SELECT JSON_ARRAY(1, 'abc', NULL, TRUE, JSON_OBJECT('key', 'value')); -- 结果: [1, "abc", null, true, {"key": "value"}]
2、查询JSON值
-
JSON_EXTRACT() / -> - 提取JSON数据
SELECT JSON_EXTRACT('{"name": "李四", "age": 30}', '$.name'); -- 或使用 -> 操作符 SELECT JSON_OBJECT('name', '王五') -> '$.name'; -- 结果: "王五"
-
->> - 提取并取消引号
SELECT JSON_OBJECT('name', '赵六') ->> '$.name'; -- 结果: 赵六 (不带引号的字符串)
-
JSON_CONTAINS() - 检查是否包含特定值
SELECT JSON_CONTAINS('[1, 2, 3]', '2', '$'); -- 结果: 1 (true)
3、修改JSON值
-
JSON_SET() - 设置值(存在则更新,不存在则添加)
SELECT JSON_SET('{"a": 1}', '$.a', 10, '$.b', 2); -- 结果: {"a": 10, "b": 2}
-
JSON_INSERT() - 仅添加新值
SELECT JSON_INSERT('{"a": 1}', '$.a', 10, '$.b', 2); -- 结果: {"a": 1, "b": 2} (a未被更新)
-
JSON_REPLACE() - 仅更新现有值
SELECT JSON_REPLACE('{"a": 1, "b": 2}', '$.a', 10, '$.c', 3); -- 结果: {"a": 10, "b": 2} (c未被添加)
-
JSON_REMOVE() - 删除元素
SELECT JSON_REMOVE('{"a": 1, "b": 2}', '$.a'); -- 结果: {"b": 2}
4、JSON路径表达式
路径表达式用于定位JSON文档中的特定部分:
$
表示文档根$.key
表示对象中的键$[n]
表示数组中的第n个元素(从0开始)$[*]
表示数组中的所有元素$.key1.key2
表示嵌套对象
5、其他实用函数
-
JSON_TYPE() - 返回JSON值的类型
SELECT JSON_TYPE('{"a": 1}'); -- OBJECT SELECT JSON_TYPE('[1, 2]'); -- ARRAY
-
JSON_LENGTH() - 返回JSON文档长度
SELECT JSON_LENGTH('[1, 2, {"a": 3}]'); -- 3
-
JSON_KEYS() - 返回对象的所有键
SELECT JSON_KEYS('{"a": 1, "b": 2}'); -- ["a", "b"]
-
JSON_SEARCH() - 搜索值并返回路径
SELECT JSON_SEARCH('{"a": 1, "b": "value"}', 'one', 'value'); -- 结果: "$.b"
6、实际应用示例
-- 创建包含JSON列的表
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50),profile JSON
);-- 插入JSON数据
INSERT INTO users (name, profile) VALUES
('张三', '{"age": 25, "hobbies": ["篮球", "音乐"], "address": {"city": "北京"}}');-- 查询JSON字段
SELECT name, profile->>'$.address.city' AS city FROM users;-- 更新JSON字段
UPDATE users
SET profile = JSON_SET(profile, '$.age', 26, '$.hobbies[2]', '阅读')
WHERE name = '张三';-- 使用JSON条件查询
SELECT name FROM users
WHERE JSON_CONTAINS(profile->'$.hobbies', '"篮球"');
五、字符串搜索和位置定位:LOCATE()
LOCATE()
是 MySQL 中用于查找子字符串位置的函数(INSTR()
是它的变体,功能类似但参数顺序不同)。
基本语法
LOCATE(substring, string [, start])
参数说明
- substring:要查找的子字符串
- string:被搜索的原始字符串
- start(可选):开始搜索的位置(从1开始计数),如果省略则从字符串开头搜索
返回值
- 返回子字符串第一次出现的位置(从1开始计数)
- 如果找不到则返回0
- 如果任一参数为NULL则返回NULL
使用示例
示例数据
使用之前的 users
表:
SELECT * FROM users;
结果:
+----+------------+
| id | username |
+----+------------+
| 1 | john_doe |
| 2 | jane_smith |
| 3 | bob123 |
+----+------------+
示例1:基本查找
-- 查找下划线位置
SELECT username, LOCATE('_', username) AS underscore_pos FROM users;
结果:
+------------+----------------+
| username | underscore_pos |
+------------+----------------+
| john_doe | 5 |
| jane_smith | 5 |
| bob123 | 0 |
+------------+----------------+
示例2:指定起始位置
-- 从第6个字符开始查找字母'e'
SELECT username, LOCATE('e', username, 6) AS e_pos FROM users;
结果:
+------------+-------+
| username | e_pos |
+------------+-------+
| john_doe | 8 | -- 'doe'中的e
| jane_smith | 0 | -- 从第6位'smith'中没有e
| bob123 | 0 |
+------------+-------+
示例3:与SUBSTRING结合使用
-- 提取下划线后的部分
SELECT username, SUBSTRING(username, LOCATE('_', username) + 1) AS after_underscore
FROM users;
结果:
+------------+------------------+
| username | after_underscore |
+------------+------------------+
| john_doe | doe |
| jane_smith | smith |
| bob123 | bob123 | -- 没有下划线,返回整个字符串
+------------+------------------+
示例4:处理找不到的情况
-- 安全提取下划线后的部分(找不到时返回NULL)
SELECT username,CASE WHEN LOCATE('_', username) > 0 THEN SUBSTRING(username, LOCATE('_', username) + 1)ELSE NULLEND AS after_underscore
FROM users;
示例5:INSTR函数(参数顺序不同)
-- INSTR(string, substring) 是 LOCATE(substring, string) 的变体
SELECT username, INSTR(username, '_') AS underscore_pos FROM users;
注意事项
- 搜索是区分大小写的,除非使用不区分大小写的排序规则
- 对于多字节字符(如中文),每个字符计为1个位置
- 如果
start
小于1,会被视为1 - 如果
start
大于字符串长度,返回0 - 空字符串
''
作为子字符串时,在有效位置范围内会返回start
参数值