MySQL 从零入门(五):MySQL 内置函数详解------日期、字符串、数学函数与实战案例

🔥 星恒随风: 个人主页 ❄️ 个人专栏: 《Linux网络编程从0到1》 | 《C语言基础》 | 《数据结构和算法》 | 《MySQL入门心法》 | 《前端基础》 | 《python基础》 | 《C++从入门到入土》 | 《Linux系统编程》 ✨ 数据即知识,压缩即智能
文章目录
- [MySQL 从零入门(五):MySQL 内置函数详解------日期、字符串、数学函数与实战案例](#MySQL 从零入门(五):MySQL 内置函数详解——日期、字符串、数学函数与实战案例)
- [一、MySQL 函数基础](#一、MySQL 函数基础)
-
- [1.1 什么是内置函数?](#1.1 什么是内置函数?)
- [1.2 SELECT 一定需要 FROM 吗?](#1.2 SELECT 一定需要 FROM 吗?)
- [1.3 MySQL 函数的分类](#1.3 MySQL 函数的分类)
- [1.4 准备实验环境](#1.4 准备实验环境)
- [二、日期函数(Date Functions)](#二、日期函数(Date Functions))
-
- [2.1 常见日期函数](#2.1 常见日期函数)
- [2.2 CURRENT_DATE():获取当前日期](#2.2 CURRENT_DATE():获取当前日期)
- [2.3 CURRENT_TIME():获取当前时间](#2.3 CURRENT_TIME():获取当前时间)
- [2.4 CURRENT_TIMESTAMP():获取当前日期和时间](#2.4 CURRENT_TIMESTAMP():获取当前日期和时间)
- 三、DATE_ADD:日期加法
-
- [3.1 基本语法](#3.1 基本语法)
- [3.2 INTERVAL 支持哪些单位?](#3.2 INTERVAL 支持哪些单位?)
- [3.3 DATE_ADD 在业务中的用途](#3.3 DATE_ADD 在业务中的用途)
- 四、DATE_SUB:日期减法
-
- [4.1 基本语法](#4.1 基本语法)
- [4.2 DATE_ADD 与 DATE_SUB 的区别](#4.2 DATE_ADD 与 DATE_SUB 的区别)
- [4.3 查询七天前的日期](#4.3 查询七天前的日期)
- 五、DATEDIFF:计算两个日期之间的天数
-
- [5.1 基本语法](#5.1 基本语法)
- [5.2 DATEDIFF 的注意事项](#5.2 DATEDIFF 的注意事项)
- 六、日期函数实战:记录用户生日
-
- [6.1 创建生日表](#6.1 创建生日表)
- [6.2 插入当前日期](#6.2 插入当前日期)
- [6.3 计算距离生日日期经过了多少天](#6.3 计算距离生日日期经过了多少天)
- 七、日期函数实战:留言系统
-
- [7.1 创建留言表](#7.1 创建留言表)
- [7.2 插入留言](#7.2 插入留言)
- [7.3 只显示发布日期,不显示时间](#7.3 只显示发布日期,不显示时间)
- [7.4 查询最近两分钟发布的留言](#7.4 查询最近两分钟发布的留言)
- [八、字符串函数(String Functions)](#八、字符串函数(String Functions))
-
- [8.1 常见字符串函数](#8.1 常见字符串函数)
- 九、CHARSET:查看字符串字符集
-
- [9.1 基本语法](#9.1 基本语法)
- [9.2 查看字段的字符集](#9.2 查看字段的字符集)
- 十、CONCAT:字符串拼接
-
- [10.1 基本语法](#10.1 基本语法)
- [10.2 拼接学生成绩](#10.2 拼接学生成绩)
- [10.3 CONCAT 与 NULL](#10.3 CONCAT 与 NULL)
- 十一、LENGTH:获取字符串字节数
-
- [11.1 基本语法](#11.1 基本语法)
- [11.2 中文字符串的字节数](#11.2 中文字符串的字节数)
- [11.3 LENGTH 与 CHAR_LENGTH](#11.3 LENGTH 与 CHAR_LENGTH)
- [11.4 查询每名学生姓名占用的字节数](#11.4 查询每名学生姓名占用的字节数)
- 十二、INSTR:查找子字符串
-
- [12.1 基本语法](#12.1 基本语法)
- [12.2 实际应用](#12.2 实际应用)
- [十三、UCASE 与 LCASE:大小写转换](#十三、UCASE 与 LCASE:大小写转换)
-
- [13.1 UCASE:转换为大写](#13.1 UCASE:转换为大写)
- [13.2 LCASE:转换为小写](#13.2 LCASE:转换为小写)
- [13.3 查询时统一大小写](#13.3 查询时统一大小写)
- [十四、LEFT 与 SUBSTRING:字符串截取](#十四、LEFT 与 SUBSTRING:字符串截取)
-
- [14.1 LEFT 函数](#14.1 LEFT 函数)
- [14.2 SUBSTRING 函数](#14.2 SUBSTRING 函数)
- [14.3 SUBSTRING 的下标规则](#14.3 SUBSTRING 的下标规则)
- [14.4 截取姓名中的部分字符](#14.4 截取姓名中的部分字符)
- [14.5 只指定起始位置](#14.5 只指定起始位置)
- 十五、REPLACE:字符串替换
-
- [15.1 基本语法](#15.1 基本语法)
- [15.2 替换姓名中的字符](#15.2 替换姓名中的字符)
- [15.3 查询时替换字符串](#15.3 查询时替换字符串)
- 十六、STRCMP:字符串比较
-
- [16.1 基本语法](#16.1 基本语法)
- 十七、TRIM:删除字符串两端的空格
-
- [17.1 为什么需要 TRIM?](#17.1 为什么需要 TRIM?)
- [17.2 TRIM](#17.2 TRIM)
- [17.3 LTRIM](#17.3 LTRIM)
- [17.4 RTRIM](#17.4 RTRIM)
- [17.5 三者区别](#17.5 三者区别)
- 十八、字符串函数综合案例:英文姓名首字母小写
- [十九、数学函数(Mathematical Functions)](#十九、数学函数(Mathematical Functions))
- 二十、ABS:绝对值函数
-
- [20.1 基本语法](#20.1 基本语法)
- [20.2 实际应用](#20.2 实际应用)
- [二十一、CEILING 与 FLOOR:向上、向下取整](#二十一、CEILING 与 FLOOR:向上、向下取整)
-
- [21.1 CEILING:向上取整](#21.1 CEILING:向上取整)
- [21.2 FLOOR:向下取整](#21.2 FLOOR:向下取整)
- [21.3 负数情况下的区别](#21.3 负数情况下的区别)
- 二十二、FORMAT:数值格式化
-
- [22.1 基本语法](#22.1 基本语法)
- [22.2 FORMAT 与 ROUND 的区别](#22.2 FORMAT 与 ROUND 的区别)
- 二十三、RAND:生成随机数
-
- [23.1 基本语法](#23.1 基本语法)
- [23.2 生成 0~9 的随机整数](#23.2 生成 0~9 的随机整数)
- [23.3 生成 1~100 的随机整数](#23.3 生成 1~100 的随机整数)
- 二十四、BIN、HEX、CONV:进制转换
-
- [24.1 BIN:转换为二进制](#24.1 BIN:转换为二进制)
- [24.2 HEX:转换为十六进制](#24.2 HEX:转换为十六进制)
- [24.3 CONV:不同进制之间转换](#24.3 CONV:不同进制之间转换)
- 二十五、MOD:取模运算
-
- [25.1 基本语法](#25.1 基本语法)
- [25.2 判断奇偶数](#25.2 判断奇偶数)
- 二十六、其他常用函数
- 二十七、USER:查看当前连接用户
- 二十八、DATABASE:查看当前数据库
- 二十九、MD5:计算字符串摘要
-
- [29.1 基本语法](#29.1 基本语法)
- [29.2 MD5 能用于保存用户密码吗?](#29.2 MD5 能用于保存用户密码吗?)
- [三十、PASSWORD:MySQL 5.7 的旧密码函数](#三十、PASSWORD:MySQL 5.7 的旧密码函数)
- [三十一、IFNULL:处理 NULL 值](#三十一、IFNULL:处理 NULL 值)
-
- [31.1 为什么需要 IFNULL?](#31.1 为什么需要 IFNULL?)
- [31.2 IFNULL 基本语法](#31.2 IFNULL 基本语法)
- [31.3 在学生表中使用 IFNULL](#31.3 在学生表中使用 IFNULL)
- [31.4 IFNULL 与 CONCAT 结合](#31.4 IFNULL 与 CONCAT 结合)
- 三十二、综合实战:留言系统的数据处理
-
- [32.1 创建留言表](#32.1 创建留言表)
- [32.2 插入数据](#32.2 插入数据)
- [32.3 查询留言内容和发布日期](#32.3 查询留言内容和发布日期)
- [32.4 查询每条留言的字符数](#32.4 查询每条留言的字符数)
- [32.5 查询包含 MySQL 的留言](#32.5 查询包含 MySQL 的留言)
- [32.6 为留言生成显示内容](#32.6 为留言生成显示内容)
- [三十三、SQL 实战:统计字符串中逗号出现的次数](#三十三、SQL 实战:统计字符串中逗号出现的次数)
-
- [33.1 题目](#33.1 题目)
- [33.2 解题思路](#33.2 解题思路)
- [33.3 SQL 实现](#33.3 SQL 实现)
- [33.4 更通用的思路](#33.4 更通用的思路)
- 三十四、常见问题总结
-
- [34.1 NOW() 和 CURRENT_DATE() 有什么区别?](#34.1 NOW() 和 CURRENT_DATE() 有什么区别?)
- [34.2 LENGTH 与 CHAR_LENGTH 有什么区别?](#34.2 LENGTH 与 CHAR_LENGTH 有什么区别?)
- [34.3 SUBSTRING 为什么从 1 开始?](#34.3 SUBSTRING 为什么从 1 开始?)
- [34.4 CONCAT 为什么可能返回 NULL?](#34.4 CONCAT 为什么可能返回 NULL?)
- [34.5 FORMAT 和 ROUND 有什么区别?](#34.5 FORMAT 和 ROUND 有什么区别?)
- [34.6 DATE_ADD 与 DATE_SUB 有什么区别?](#34.6 DATE_ADD 与 DATE_SUB 有什么区别?)
- [34.7 使用函数会修改原始数据吗?](#34.7 使用函数会修改原始数据吗?)
- [34.8 MD5 可以用于用户密码吗?](#34.8 MD5 可以用于用户密码吗?)
- [三十五、常用 MySQL 内置函数速查表](#三十五、常用 MySQL 内置函数速查表)
-
- [35.1 日期函数](#35.1 日期函数)
- [35.2 字符串函数](#35.2 字符串函数)
- [35.3 数学函数](#35.3 数学函数)
- [35.4 其他函数](#35.4 其他函数)
- 三十六、总结
前言
在上一篇《MySQL 从零入门(四):表的增删改查与基础查询详解》中,我们学习了 MySQL 的 CRUD 操作,包括 INSERT、SELECT、UPDATE、DELETE,以及 WHERE、ORDER BY、GROUP BY 等常用 SQL 语法。
但是,在实际开发过程中,仅仅查询和修改数据还不够。
例如:
- 如何获取服务器当前的日期和时间?
- 如何查询最近两分钟内发布的留言?
- 如何计算两个日期之间相差多少天?
- 如何拼接多个字符串?
- 如何截取字符串的一部分?
- 如何统计中文字符串的字符数和字节数?
- 如何对小数进行四舍五入?
- 如何处理查询结果中的 NULL?
这些需求都可以使用 MySQL 提供的 内置函数(Built-in Functions) 实现。
内置函数可以帮助我们直接在 SQL 中完成日期计算、字符串处理、数学运算和数据转换,从而减少应用程序中重复编写的简单处理逻辑。
本文将系统介绍 MySQL 5.7 中常用的内置函数,并通过实际 SQL 案例帮助初学者理解其工作原理。
一、MySQL 函数基础
1.1 什么是内置函数?
函数可以简单理解为:
接收输入参数,执行某种操作,然后返回结果。
例如,在 C/C++ 中,我们可能使用:
cpp
int abs(int x);
计算一个整数的绝对值。
MySQL 同样提供了类似的函数:
sql
SELECT ABS(-100);
查询结果:
text
+-----------+
| ABS(-100) |
+-----------+
| 100 |
+-----------+
这里:
SELECT:查询结果。ABS:绝对值函数。-100:输入参数。100:函数的返回值。
与之前学习的普通 SELECT 不同,这里并不需要从数据表中读取记录。
1.2 SELECT 一定需要 FROM 吗?
不一定。
例如:
sql
SELECT 1 + 2;
结果:
text
3
再例如:
sql
SELECT ABS(-10);
结果:
text
10
这两条 SQL 都没有使用 FROM。
因为 MySQL 支持直接计算表达式或调用函数。
需要注意:MySQL 内置函数既可以单独调用,也可以结合数据表中的字段使用。
例如:
sql
SELECT ABS(-100);
是对固定数值进行计算。
而:
sql
SELECT ABS(score)
FROM student;
则是对 student 表中每条记录的 score 字段进行计算。
1.3 MySQL 函数的分类
常见函数可以分为以下几类:
| 分类 | 主要用途 | 代表函数 |
|---|---|---|
| 日期函数 | 日期和时间处理 | NOW、DATE_ADD、DATEDIFF |
| 字符串函数 | 字符串拼接、截取和替换 | CONCAT、SUBSTRING、REPLACE |
| 数学函数 | 数值计算和格式化 | ABS、CEILING、FLOOR |
| 系统及其他函数 | 获取连接信息、处理 NULL 等 | USER、DATABASE、IFNULL |
上一篇介绍的:
sql
COUNT()
SUM()
AVG()
MAX()
MIN()
也属于 MySQL 内置函数,不过它们通常被归类为聚合函数。
本文主要学习标量函数,即通常对一组输入计算并返回一个值的函数。
1.4 准备实验环境
首先进入 MySQL:
bash
mycli -h 127.0.0.1 -P 3306 -u root
创建专用实验数据库:
sql
CREATE DATABASE IF NOT EXISTS lab07
CHARACTER SET utf8
COLLATE utf8_general_ci;
切换数据库:
sql
USE lab07;
查看当前数据库:
sql
SELECT DATABASE();
预期结果:
text
+------------+
| DATABASE() |
+------------+
| lab07 |
+------------+
后续实验均在 lab07 中完成。
二、日期函数(Date Functions)
日期函数用于处理日期、时间以及两个时间点之间的关系。
例如:
- 当前日期是多少?
- 当前时间是多少?
- 十天之后是哪一天?
- 两个日期相差多少天?
- 某条留言是否在最近两分钟内发布?
2.1 常见日期函数
| 函数 | 作用 |
|---|---|
CURRENT_DATE() |
获取当前日期 |
CURRENT_TIME() |
获取当前时间 |
CURRENT_TIMESTAMP() |
获取当前日期和时间 |
NOW() |
获取当前日期和时间 |
DATE(datetime) |
提取日期部分 |
DATE_ADD() |
日期或时间加上指定间隔 |
DATE_SUB() |
日期或时间减去指定间隔 |
DATEDIFF() |
计算两个日期之间相差的天数 |
下面逐个介绍。
2.2 CURRENT_DATE():获取当前日期
执行:
sql
SELECT CURRENT_DATE();
假设当前日期为 2026 年 11 月 12 日,那么返回:
text
+----------------+
| CURRENT_DATE() |
+----------------+
| 2026-11-12 |
+----------------+
返回值通常采用:
text
YYYY-MM-DD
格式。
其中:
- YYYY:年份。
- MM:月份。
- DD:日期。
注意,实际结果由 MySQL 当前日期以及会话时区等因素决定。
另外,也可以使用:
sql
SELECT CURDATE();
它与 CURRENT_DATE() 具有相同用途。
2.3 CURRENT_TIME():获取当前时间
执行:
sql
SELECT CURRENT_TIME();
可能得到:
text
+----------------+
| CURRENT_TIME() |
+----------------+
| 15:30:25 |
+----------------+
返回格式通常为:
text
HH:MM:SS
其中:
- HH:小时。
- MM:分钟。
- SS:秒。
它只返回时间部分,不包含日期。
也可以使用:
sql
SELECT CURTIME();
2.4 CURRENT_TIMESTAMP():获取当前日期和时间
执行:
sql
SELECT CURRENT_TIMESTAMP();
可能得到:
text
2026-11-12 15:30:25
返回值包含日期和时间。
也可以执行:
sql
SELECT NOW();
两者在这里具有相同用途。
因此,可以总结:
| 函数 | 返回内容 |
|---|---|
| CURRENT_DATE() | 年、月、日 |
| CURRENT_TIME() | 时、分、秒 |
| CURRENT_TIMESTAMP() | 年、月、日、时、分、秒 |
| NOW() | 年、月、日、时、分、秒 |
如果业务需要记录一条消息的发送时间,就可以使用 NOW()。
三、DATE_ADD:日期加法
3.1 基本语法
sql
DATE_ADD(日期, INTERVAL 数值 时间单位)
例如:
sql
SELECT DATE_ADD('2017-10-28', INTERVAL 10 DAY);
结果:
text
2017-11-07
逐个解释:
| 部分 | 含义 |
|---|---|
| DATE_ADD | 日期加法函数 |
'2017-10-28' |
原始日期 |
| INTERVAL | 指定时间间隔 |
| 10 | 增加的数量 |
| DAY | 时间单位:天 |
整条 SQL 的意思是:
在 2017 年 10 月 28 日的基础上增加 10 天。
3.2 INTERVAL 支持哪些单位?
常见时间单位包括:
| 单位 | 含义 |
|---|---|
| YEAR | 年 |
| MONTH | 月 |
| DAY | 天 |
| HOUR | 小时 |
| MINUTE | 分钟 |
| SECOND | 秒 |
例如:
增加一年:
sql
SELECT DATE_ADD('2026-01-01', INTERVAL 1 YEAR);
增加一个月:
sql
SELECT DATE_ADD('2026-01-01', INTERVAL 1 MONTH);
增加三天:
sql
SELECT DATE_ADD('2026-01-01', INTERVAL 3 DAY);
增加两个小时:
sql
SELECT DATE_ADD('2026-01-01 12:00:00', INTERVAL 2 HOUR);
其中最后一条 SQL 会返回:
text
2026-01-01 14:00:00
3.3 DATE_ADD 在业务中的用途
假设用户购买了一个有效期为 30 天的会员。
可以计算到期时间:
sql
SELECT DATE_ADD(NOW(), INTERVAL 30 DAY);
如果当前时间为:
text
2026-11-12 15:30:00
那么到期时间为:
text
2026-12-12 15:30:00
实际系统通常会在购买时计算并保存到期时间,而不是每次查询时都以当前时间作为起点重新计算。
四、DATE_SUB:日期减法
4.1 基本语法
sql
DATE_SUB(日期, INTERVAL 数值 时间单位)
例如:
sql
SELECT DATE_SUB('2017-10-01', INTERVAL 2 DAY);
结果:
text
2017-09-29
这条 SQL 的意思是:
从 2017 年 10 月 1 日减去两天。
4.2 DATE_ADD 与 DATE_SUB 的区别
| 函数 | 作用 |
|---|---|
| DATE_ADD | 增加指定时间间隔 |
| DATE_SUB | 减去指定时间间隔 |
例如:
sql
SELECT DATE_ADD('2026-11-12', INTERVAL 7 DAY);
表示七天之后。
sql
SELECT DATE_SUB('2026-11-12', INTERVAL 7 DAY);
表示七天之前。
4.3 查询七天前的日期
sql
SELECT DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY);
这一表达式在实际业务中很常见。
例如,查询最近七天的订单时,可以使用计算出来的日期作为筛选条件。
五、DATEDIFF:计算两个日期之间的天数
5.1 基本语法
sql
DATEDIFF(date1, date2)
表示:
date1 的日期减去 date2 的日期,返回相差的天数。
例如:
sql
SELECT DATEDIFF('2017-10-10', '2016-09-01');
结果:
text
404
如果交换两个日期的位置:
sql
SELECT DATEDIFF('2016-09-01', '2017-10-10');
结果:
text
-404
说明 DATEDIFF 的计算结果可以为负数。
5.2 DATEDIFF 的注意事项
DATEDIFF 主要计算日期部分的差值。
例如:
sql
SELECT DATEDIFF(
'2026-11-12 23:59:59',
'2026-11-11 00:00:01'
);
结果为:
text
1
虽然两个时间点之间接近两天,但是日期部分只相差一天。
因此,不应该使用 DATEDIFF 计算精确到小时、分钟或秒的时间差。
如果需要更精细的时间差,可以考虑 MySQL 的 TIMESTAMPDIFF 等函数。
六、日期函数实战:记录用户生日
6.1 创建生日表
sql
CREATE TABLE birthday_demo (
id INT PRIMARY KEY AUTO_INCREMENT,
birthday DATE
);
字段说明:
- id:自增长主键。
- birthday:生日日期。
6.2 插入当前日期
sql
INSERT INTO birthday_demo(birthday)
VALUES (CURRENT_DATE());
这里没有指定 id。
因为:
sql
AUTO_INCREMENT
会自动生成编号。
而:
sql
CURRENT_DATE()
会返回当前日期。
查询:
sql
SELECT * FROM birthday_demo;
假设执行日期为 2026 年 11 月 12 日:
text
+----+------------+
| id | birthday |
+----+------------+
| 1 | 2026-11-12 |
+----+------------+
6.3 计算距离生日日期经过了多少天
sql
SELECT
id,
birthday,
DATEDIFF(CURRENT_DATE(), birthday) AS days_passed
FROM birthday_demo;
其中:
sql
AS days_passed
表示为计算结果设置别名。
注意,这里计算的是距离字段中保存的日期经过的天数,并不等同于正确计算一个人的周岁年龄。
七、日期函数实战:留言系统
这是一个更接近实际后端开发的例子。
假设我们开发一个简单的留言系统,每条留言需要保存:
- 留言编号。
- 留言内容。
- 发布时间。
7.1 创建留言表
sql
CREATE TABLE msg (
id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(30) NOT NULL,
sendtime DATETIME
);
这里:
sql
sendtime DATETIME
表示保存留言的发布时间。
7.2 插入留言
sql
INSERT INTO msg(content, sendtime)
VALUES ('hello1', NOW());
再插入一条:
sql
INSERT INTO msg(content, sendtime)
VALUES ('hello2', NOW());
查询:
sql
SELECT * FROM msg;
结果可能类似:
text
+----+---------+---------------------+
| id | content | sendtime |
+----+---------+---------------------+
| 1 | hello1 | 2026-11-12 15:30:00 |
| 2 | hello2 | 2026-11-12 15:31:00 |
+----+---------+---------------------+
注意,实际执行时间不同,返回的 sendtime 也会不同。
7.3 只显示发布日期,不显示时间
需求:
留言发布时间原本包含:
text
2026-11-12 15:30:00
现在只希望显示:
text
2026-11-12
可以使用:
sql
SELECT
content,
DATE(sendtime) AS publish_date
FROM msg;
其中:
sql
DATE(sendtime)
会提取日期部分。
注意,这只是改变查询结果的表现形式,不会修改数据库中实际保存的 DATETIME 值。
7.4 查询最近两分钟发布的留言
这是一个典型的时间范围查询。
可以使用:
sql
SELECT *
FROM msg
WHERE DATE_ADD(sendtime, INTERVAL 2 MINUTE) > NOW();
这条 SQL 的含义是:
如果留言发送时间加两分钟仍然晚于当前时间,那么认为留言处于两分钟的有效区间内。
可以理解为:
text
留言发送时间 当前时间
|----------------------------|
小于 2 分钟
不过,这种写法没有排除未来时间。
因此,更严谨的"最近两分钟"查询可以写成:
sql
SELECT *
FROM msg
WHERE sendtime >= DATE_SUB(NOW(), INTERVAL 2 MINUTE)
AND sendtime <= NOW();
逐个解释:
sql
DATE_SUB(NOW(), INTERVAL 2 MINUTE)
表示当前时间减去两分钟。
sql
sendtime >= ...
表示留言发布时间不能早于两分钟前。
sql
sendtime <= NOW()
表示留言发布时间不能晚于当前时间。
因此,只有真正处于过去两分钟内的记录才会被匹配。
另外,把函数作用在常量或当前时间一侧,而不是直接作用在 sendtime 字段上,通常也更有利于利用该字段的普通索引进行范围查询。
八、字符串函数(String Functions)
字符串函数主要用于处理文本数据。
例如:
- 拼接姓名和成绩。
- 统计字符串长度。
- 将英文转换为大写或小写。
- 查找某个子串的位置。
- 替换指定字符串。
- 截取姓名的一部分。
- 删除字符串两端的空格。
8.1 常见字符串函数
| 函数 | 作用 |
|---|---|
| CHARSET(str) | 返回字符串使用的字符集 |
| CONCAT(str1, str2, ...) | 拼接字符串 |
| INSTR(str, substr) | 查找子串首次出现的位置 |
| UCASE(str) | 转换为大写 |
| LCASE(str) | 转换为小写 |
| LEFT(str, n) | 获取左侧 n 个字符 |
| LENGTH(str) | 获取字符串的字节数 |
| REPLACE(str, from, to) | 替换字符串 |
| STRCMP(str1, str2) | 比较字符串 |
| SUBSTRING(str, pos, len) | 截取子字符串 |
| LTRIM(str) | 删除左侧空格 |
| RTRIM(str) | 删除右侧空格 |
| TRIM(str) | 删除两侧空格 |
下面分别介绍。
九、CHARSET:查看字符串字符集
9.1 基本语法
sql
CHARSET(str)
表示返回字符串使用的字符集名称。
例如:
sql
SELECT CHARSET('hello');
返回结果取决于当前连接中字符串表达式使用的字符集。
如果当前连接使用 utf8,可以得到:
text
utf8
9.2 查看字段的字符集
首先创建一张测试表:
sql
CREATE TABLE string_demo (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30),
content VARCHAR(100)
) CHARACTER SET utf8;
插入数据:
sql
INSERT INTO string_demo(name, content)
VALUES
('ZhangSan', 'Hello World'),
('LiSi', 'MySQL Database'),
('张三', '我正在学习MySQL');
查询:
sql
SELECT CHARSET(name)
FROM string_demo;
在该示例中,name 字段采用 utf8 字符集。
因此结果为:
text
utf8
十、CONCAT:字符串拼接
10.1 基本语法
sql
CONCAT(str1, str2, str3, ...)
它可以将多个字符串连接成一个字符串。
例如:
sql
SELECT CONCAT('Hello', ' ', 'MySQL');
结果:
text
Hello MySQL
其中:
'Hello':第一个字符串。' ':一个空格字符。'MySQL':第三个字符串。
CONCAT 按顺序将它们拼接起来。
10.2 拼接学生成绩
假设我们有一张成绩表:
sql
CREATE TABLE exam_result (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
chinese INT,
math INT,
english INT
);
插入:
sql
INSERT INTO exam_result(name, chinese, math, english)
VALUES
('张三', 85, 90, 88),
('李四', 78, 92, 80),
('王五', 95, 87, 91);
现在希望以自然语言显示:
text
张三的语文是85分,数学是90分,英语是88分
可以执行:
sql
SELECT CONCAT(
name,
'的语文是', chinese,
'分,数学是', math,
'分,英语是', english,
'分'
) AS 成绩信息
FROM exam_result;
结果:
text
张三的语文是85分,数学是90分,英语是88分
李四的语文是78分,数学是92分,英语是80分
王五的语文是95分,数学是87分,英语是91分
这里利用 CONCAT 将字符串常量与表字段连接起来。
10.3 CONCAT 与 NULL
需要特别注意:
MySQL 中如果 CONCAT 的任意参数为 NULL,结果通常也是 NULL。
例如:
sql
SELECT CONCAT('Hello', NULL, 'World');
结果:
text
NULL
因此,如果需要拼接可能为 NULL 的字段,可以配合后面介绍的 IFNULL 函数处理。
十一、LENGTH:获取字符串字节数
11.1 基本语法
sql
LENGTH(str)
返回字符串占用的字节数。
例如:
sql
SELECT LENGTH('hello');
结果:
text
5
因为字符串 hello 由五个 ASCII 字符组成,在 UTF-8 中通常每个占用一个字节。
11.2 中文字符串的字节数
例如:
sql
SELECT LENGTH('中国');
在 MySQL 5.7 的 utf8 字符集中,通常返回:
text
6
因为:
text
中 → 3 字节
国 → 3 字节
因此:
text
2 × 3 = 6 字节
这里有一个重要区别:
字符数不一定等于字节数。
11.3 LENGTH 与 CHAR_LENGTH
虽然 LENGTH 返回字节数,但 MySQL 还提供:
sql
CHAR_LENGTH(str)
用于返回字符数量。
例如:
sql
SELECT
LENGTH('中国') AS bytes,
CHAR_LENGTH('中国') AS characters;
在 utf8 字符集下,结果为:
text
+-------+------------+
| bytes | characters |
+-------+------------+
| 6 | 2 |
+-------+------------+
因此:
| 函数 | 含义 |
|---|---|
| LENGTH | 字节数 |
| CHAR_LENGTH | 字符数 |
这个区别对于处理中文字符串非常重要。
11.4 查询每名学生姓名占用的字节数
sql
SELECT
name,
LENGTH(name) AS bytes
FROM string_demo;
如果还想显示字符数:
sql
SELECT
name,
LENGTH(name) AS bytes,
CHAR_LENGTH(name) AS characters
FROM string_demo;
需要注意,字节数受字符集编码影响。
同样的字符,在不同字符集中可能占用不同数量的字节。
十二、INSTR:查找子字符串
12.1 基本语法
sql
INSTR(str, substr)
作用:
在字符串 str 中查找子字符串 substr 第一次出现的位置。
例如:
sql
SELECT INSTR('Hello MySQL', 'MySQL');
结果:
text
7
因为 MySQL 从整个字符串的第七个字符开始。
需要注意:
MySQL 的 INSTR 函数位置从 1 开始,而不是从 0 开始。
如果找不到:
sql
SELECT INSTR('Hello MySQL', 'Python');
返回:
text
0
12.2 实际应用
查询 content 中包含 MySQL 的记录:
sql
SELECT *
FROM string_demo
WHERE INSTR(content, 'MySQL') > 0;
这里:
sql
INSTR(content, 'MySQL') > 0
表示 content 字段中存在字符串 MySQL。
不过,这类包含查询也可以使用 LIKE 实现。
十三、UCASE 与 LCASE:大小写转换
13.1 UCASE:转换为大写
例如:
sql
SELECT UCASE('hello mysql');
结果:
text
HELLO MYSQL
13.2 LCASE:转换为小写
例如:
sql
SELECT LCASE('HELLO MYSQL');
结果:
text
hello mysql
另外,MySQL 还支持:
sql
UPPER()
LOWER()
它们分别与 UCASE、LCASE 对应。
13.3 查询时统一大小写
例如:
sql
SELECT
name,
UCASE(name) AS upper_name,
LCASE(name) AS lower_name
FROM string_demo;
对于英文姓名,可以查看转换前后的差异。
对于中文字符,通常不会产生英文字母那样的大小写变化。
需要注意,大小写转换函数主要改变查询结果。如果只是使用 SELECT,不会修改数据库中保存的原始字符串。
十四、LEFT 与 SUBSTRING:字符串截取
14.1 LEFT 函数
基本语法:
sql
LEFT(str, n)
表示从字符串左侧取 n 个字符。
例如:
sql
SELECT LEFT('Hello MySQL', 5);
返回:
text
Hello
14.2 SUBSTRING 函数
基本语法:
sql
SUBSTRING(str, pos, len)
其中:
- str:原始字符串。
- pos:开始位置。
- len:截取的字符数量。
例如:
sql
SELECT SUBSTRING('abcdef', 2, 2);
返回:
text
bc
因为从第二个字符开始,截取两个字符。
14.3 SUBSTRING 的下标规则
MySQL 字符串位置通常从 1 开始。
例如:
text
字符串:a b c d e f
位置: 1 2 3 4 5 6
因此:
sql
SUBSTRING('abcdef', 2, 2)
表示:
text
从第 2 个字符开始,取 2 个字符
结果为:
text
bc
这一点与 C/C++ 中数组下标通常从 0 开始不同。
14.4 截取姓名中的部分字符
例如:
sql
SELECT SUBSTRING('张三丰', 2, 2);
结果:
text
三丰
14.5 只指定起始位置
SUBSTRING 还可以省略长度:
sql
SELECT SUBSTRING('abcdef', 3);
结果:
text
cdef
表示从第三个字符开始,一直截取到字符串末尾。
十五、REPLACE:字符串替换
15.1 基本语法
sql
REPLACE(str, from_str, to_str)
其中:
- str:原始字符串。
- from_str:需要替换的内容。
- to_str:替换后的内容。
例如:
sql
SELECT REPLACE('Hello MySQL', 'MySQL', 'World');
结果:
text
Hello World
15.2 替换姓名中的字符
例如:
sql
SELECT REPLACE('Sam Smith', 'S', '上海');
结果:
text
上海am 上海mith
这是因为 REPLACE 会替换所有匹配的子字符串,而不只是第一个。
15.3 查询时替换字符串
sql
SELECT
name,
REPLACE(name, 'S', '上海') AS replaced_name
FROM string_demo;
这里仅修改查询输出。
不会直接修改数据库中原有的 name 值。
如果希望把替换结果永久写回数据库,需要配合 UPDATE。
例如:
sql
UPDATE string_demo
SET name = REPLACE(name, 'S', '上海')
WHERE name LIKE '%S%';
注意,这会真正修改数据,应先确认 WHERE 的匹配范围。
十六、STRCMP:字符串比较
16.1 基本语法
sql
STRCMP(str1, str2)
作用:
按照字符串比较规则比较两个字符串。
返回值通常有三种:
| 返回值 | 含义 |
|---|---|
| -1 | 第一个字符串小于第二个 |
| 0 | 两个字符串相等 |
| 1 | 第一个字符串大于第二个 |
例如:
sql
SELECT STRCMP('abc', 'abc');
结果:
text
0
再例如:
sql
SELECT STRCMP('abc', 'abd');
通常返回:
text
-1
需要注意,字符串比较结果可能受到字符集和校验规则的影响。
十七、TRIM:删除字符串两端的空格
17.1 为什么需要 TRIM?
假设用户输入的姓名为:
text
' ZhangSan '
字符串左边和右边都带有空格。
如果业务希望去除这些多余空格,就可以使用 TRIM。
17.2 TRIM
sql
SELECT TRIM(' hello ');
返回:
text
hello
默认删除字符串两端的普通空格。
但不会自动删除中间的空格。
例如:
sql
SELECT TRIM(' hello world ');
结果:
text
hello world
17.3 LTRIM
sql
SELECT LTRIM(' hello ');
删除左侧空格。
结果相当于:
text
'hello '
17.4 RTRIM
sql
SELECT RTRIM(' hello ');
删除右侧空格。
结果相当于:
text
' hello'
17.5 三者区别
| 函数 | 作用 |
|---|---|
| LTRIM | 删除左侧空格 |
| RTRIM | 删除右侧空格 |
| TRIM | 删除两侧空格 |
需要注意,默认的 TRIM 主要处理空格字符,不等于自动清理所有不可见字符。
十八、字符串函数综合案例:英文姓名首字母小写
假设某个员工的英文姓名是:
text
ZHANGSAN
现在希望显示为:
text
zHANGSAN
也就是只把第一个字符转换成小写,剩下的字符保持原样。
可以执行:
sql
SELECT CONCAT(
LCASE(SUBSTRING('ZHANGSAN', 1, 1)),
SUBSTRING('ZHANGSAN', 2)
);
这条 SQL 看起来有些复杂,我们从内向外分析。
第一步:
sql
SUBSTRING('ZHANGSAN', 1, 1)
截取第一个字符:
text
Z
第二步:
sql
LCASE('Z')
将其转换为小写:
text
z
第三步:
sql
SUBSTRING('ZHANGSAN', 2)
从第二个字符开始截取到末尾:
text
HANGSAN
第四步:
sql
CONCAT('z', 'HANGSAN')
拼接结果:
text
zHANGSAN
如果希望对表中的 name 字段执行类似操作:
sql
SELECT CONCAT(
LCASE(SUBSTRING(name, 1, 1)),
SUBSTRING(name, 2)
) AS new_name
FROM string_demo;
这个案例说明:
MySQL 内置函数不仅能够单独使用,还可以相互嵌套,完成更复杂的数据处理。
十九、数学函数(Mathematical Functions)
除了字符串处理,MySQL 还提供了大量数学函数。
常见函数包括:
| 函数 | 作用 |
|---|---|
| ABS() | 计算绝对值 |
| BIN() | 转换为二进制字符串 |
| HEX() | 转换为十六进制形式 |
| CONV() | 进制转换 |
| CEILING() | 向上取整 |
| FLOOR() | 向下取整 |
| FORMAT() | 数值格式化 |
| RAND() | 生成随机数 |
| MOD() | 求余数 |
二十、ABS:绝对值函数
20.1 基本语法
sql
ABS(number)
表示返回 number 的绝对值。
例如:
sql
SELECT ABS(-100.2);
结果:
text
100.2
再例如:
sql
SELECT ABS(50);
返回:
text
50
数学上,绝对值可以理解为一个数与 0 的距离。
例如:
∣ − 10 ∣ = 10 |-10|=10 ∣−10∣=10
∣ 10 ∣ = 10 |10|=10 ∣10∣=10
20.2 实际应用
假设需要计算两个学生成绩之间的差距。
sql
SELECT ABS(90 - 75);
结果:
text
15
无论谁的成绩更高,绝对值都可以表示非负的差值大小。
二十一、CEILING 与 FLOOR:向上、向下取整
21.1 CEILING:向上取整
基本语法:
sql
CEILING(number)
例如:
sql
SELECT CEILING(23.04);
结果:
text
24
因为 24 是大于或等于 23.04 的最小整数。
21.2 FLOOR:向下取整
基本语法:
sql
FLOOR(number)
例如:
sql
SELECT FLOOR(23.7);
结果:
text
23
因为 23 是小于或等于 23.7 的最大整数。
21.3 负数情况下的区别
例如:
sql
SELECT CEILING(-2.3);
结果:
text
-2
而:
sql
SELECT FLOOR(-2.3);
结果:
text
-3
为什么?
因为:
− 3 < − 2.3 < − 2 -3 < -2.3 < -2 −3<−2.3<−2
所以:
- 向上取整得到 -2。
- 向下取整得到 -3。
注意,向下取整并不等于简单删除小数部分。
二十二、FORMAT:数值格式化
22.1 基本语法
sql
FORMAT(number, decimal_places)
其中:
- number:需要格式化的数值。
- decimal_places:保留的小数位数。
例如:
sql
SELECT FORMAT(12.3456, 2);
结果:
text
12.35
这里会进行相应的舍入处理。
22.2 FORMAT 与 ROUND 的区别
MySQL 还提供常用的:
sql
ROUND(number, decimal_places)
例如:
sql
SELECT ROUND(12.3456, 2);
结果:
text
12.35
但是两者存在重要区别:
FORMAT 返回的是格式化后的字符串,而 ROUND 返回的是数值结果。
例如:
sql
SELECT FORMAT(12345.678, 2);
默认格式可能为:
text
12,345.68
这里包含千位分隔符。
而:
sql
SELECT ROUND(12345.678, 2);
结果为数值:
text
12345.68
所以:
- 如果需要面向用户显示数字,可以考虑 FORMAT。
- 如果还需要继续数值计算,通常更适合使用 ROUND 或原始数值。
二十三、RAND:生成随机数
23.1 基本语法
sql
RAND()
用于生成一个随机浮点数。
执行:
sql
SELECT RAND();
可能得到:
text
0.428392
再次执行:
sql
SELECT RAND();
可能得到:
text
0.873251
每次执行通常会得到不同结果。
RAND() 返回的数值范围是:
0 ≤ R A N D ( ) < 1 0 \le RAND() < 1 0≤RAND()<1
23.2 生成 0~9 的随机整数
可以结合 FLOOR:
sql
SELECT FLOOR(RAND() * 10);
分析:
第一步:
sql
RAND()
生成:
[ 0 , 1 ) [0,1) [0,1)
之间的随机数。
第二步:
sql
RAND() * 10
得到:
[ 0 , 10 ) [0,10) [0,10)
第三步:
sql
FLOOR(...)
向下取整。
最终得到:
text
0~9
之间的整数。
23.3 生成 1~100 的随机整数
sql
SELECT FLOOR(RAND() * 100) + 1;
结果范围为:
text
1~100
注意,RAND 适用于普通随机化需求,但不应该用于生成密码、令牌等安全敏感数据。
二十四、BIN、HEX、CONV:进制转换
24.1 BIN:转换为二进制
sql
SELECT BIN(10);
结果:
text
1010
因为:
10 10 = 1010 2 10_{10}=1010_2 1010=10102
这里的下标表示进制。
24.2 HEX:转换为十六进制
sql
SELECT HEX(255);
结果:
text
FF
因为:
255 10 = F F 16 255_{10}=FF_{16} 25510=FF16
需要注意,HEX 对数值参数和字符串参数的处理方式并不完全相同。
例如:
sql
SELECT HEX('A');
返回:
text
41
这里得到的是字符串 'A' 的字节对应的十六进制形式。
24.3 CONV:不同进制之间转换
基本语法:
sql
CONV(number, from_base, to_base)
其中:
- number:待转换的数值。
- from_base:原始进制。
- to_base:目标进制。
例如:
sql
SELECT CONV('1010', 2, 10);
表示把二进制 1010 转换成十进制。
结果:
text
10
再例如:
sql
SELECT CONV('FF', 16, 10);
结果:
text
255
这几个函数在理解二进制、位运算和数据库 BIT 类型时很有帮助。
二十五、MOD:取模运算
25.1 基本语法
sql
MOD(number, denominator)
表示计算余数。
例如:
sql
SELECT MOD(10, 3);
结果:
text
1
因为:
10 = 3 × 3 + 1 10=3\times3+1 10=3×3+1
25.2 判断奇偶数
例如:
sql
SELECT MOD(10, 2);
结果:
text
0
说明 10 可以被 2 整除。
而:
sql
SELECT MOD(11, 2);
结果:
text
1
说明 11 为奇数。
如果某张表有一个整数 id 字段,可以执行:
sql
SELECT *
FROM student
WHERE MOD(id, 2) = 0;
查询 id 为偶数的记录。
二十六、其他常用函数
除了日期、字符串和数学函数,MySQL 还提供了一些常用的系统与辅助函数。
| 函数 | 作用 |
|---|---|
| USER() | 返回当前连接的用户及来源信息 |
| DATABASE() | 返回当前选中的数据库 |
| MD5() | 计算字符串的 MD5 摘要 |
| PASSWORD() | MySQL 5.7 中的旧密码哈希函数 |
| IFNULL() | 处理 NULL 值 |
二十七、USER:查看当前连接用户
执行:
sql
SELECT USER();
可能返回:
text
root@localhost
或者:
text
root@127.0.0.1
具体内容由实际连接方式决定。
USER() 返回连接时使用的用户名及客户端来源信息。
如果想查看当前连接通过权限检查后使用的 MySQL 账户身份,还可以执行:
sql
SELECT CURRENT_USER();
两者在某些身份验证或权限配置场景下可能不同。
二十八、DATABASE:查看当前数据库
执行:
sql
SELECT DATABASE();
如果当前使用:
sql
USE lab07;
那么结果为:
text
lab07
如果当前没有选择默认数据库,则可能返回:
text
NULL
这与之前遇到的:
text
ERROR 1046 (3D000): No database selected
有关。
当我们重新登录 MySQL 后,如果没有指定默认数据库,就需要再次使用:
sql
USE lab07;
二十九、MD5:计算字符串摘要
29.1 基本语法
sql
MD5(str)
它会对输入字符串计算 MD5 摘要,通常返回 32 个十六进制字符。
例如:
sql
SELECT MD5('admin');
结果:
text
21232f297a57a5a743894a0e4a801fc3
需要注意:
MD5 是哈希摘要算法,而不是可逆加密算法。
它将输入转换为固定长度摘要,并不提供从摘要直接还原原文的解密过程。
29.2 MD5 能用于保存用户密码吗?
不建议。
因为 MD5 的计算速度非常快,而且存在已知安全弱点,不适合直接保存现代应用系统的用户密码。
实际开发中,应优先使用专门的密码哈希方案,例如:
- Argon2id
- bcrypt
- scrypt
因此,MySQL 的 MD5 函数更适合作为理解哈希摘要概念的基础示例,而不是用户认证系统的密码存储方案。
三十、PASSWORD:MySQL 5.7 的旧密码函数
MySQL 5.7 中存在:
sql
PASSWORD(str)
例如:
sql
SELECT PASSWORD('root');
可能得到:
text
*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
这个函数与 MySQL 早期账户密码认证机制有关。
需要特别说明:
PASSWORD() 不是给普通业务系统保存用户密码的通用安全函数。
它属于 MySQL 旧版本的特定功能,在后续 MySQL 版本中已经被移除。
因此,对于 MySQL 5.7,可以了解这个函数的历史用途,但不应该在新的业务系统中依赖它。
三十一、IFNULL:处理 NULL 值
31.1 为什么需要 IFNULL?
在前面的学习中,我们已经知道:
sql
SELECT 1 + NULL;
结果为:
text
NULL
这是因为 NULL 代表未知值。
但是在某些业务中,我们希望:
如果某个字段为空,就显示一个默认值。
例如:
用户没有填写昵称时,显示:
text
未设置昵称
这时可以使用 IFNULL。
31.2 IFNULL 基本语法
sql
IFNULL(value1, value2)
含义是:
- 如果 value1 不为 NULL,返回 value1。
- 如果 value1 为 NULL,返回 value2。
例如:
sql
SELECT IFNULL('abc', '123');
返回:
text
abc
因为第一个参数不是 NULL。
再例如:
sql
SELECT IFNULL(NULL, '123');
返回:
text
123
31.3 在学生表中使用 IFNULL
创建:
sql
CREATE TABLE user_demo (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(30) NOT NULL,
nickname VARCHAR(30)
);
插入:
sql
INSERT INTO user_demo(username, nickname)
VALUES
('zhangsan', '老张'),
('lisi', NULL),
('wangwu', '小王');
查询:
sql
SELECT *
FROM user_demo;
结果:
text
+----+----------+----------+
| id | username | nickname |
+----+----------+----------+
| 1 | zhangsan | 老张 |
| 2 | lisi | NULL |
| 3 | wangwu | 小王 |
+----+----------+----------+
现在希望:
当 nickname 为 NULL 时,显示"未设置昵称"。
可以执行:
sql
SELECT
username,
IFNULL(nickname, '未设置昵称') AS nickname
FROM user_demo;
结果:
text
+----------+--------------+
| username | nickname |
+----------+--------------+
| zhangsan | 老张 |
| lisi | 未设置昵称 |
| wangwu | 小王 |
+----------+--------------+
需要注意:
IFNULL 只是改变查询结果。
它不会自动把原表中的 NULL 修改成"未设置昵称"。
31.4 IFNULL 与 CONCAT 结合
前面我们提到,如果 CONCAT 的参数包含 NULL,那么整个结果可能变成 NULL。
例如:
sql
SELECT CONCAT('昵称:', NULL);
返回:
text
NULL
因此,可以使用:
sql
SELECT CONCAT(
'昵称:',
IFNULL(nickname, '未设置')
)
FROM user_demo;
这样就可以避免因为 nickname 为 NULL 而导致整条拼接结果为 NULL。
三十二、综合实战:留言系统的数据处理
下面综合使用日期函数、字符串函数和其他辅助函数,完成一个简单的留言管理场景。
32.1 创建留言表
sql
CREATE TABLE message_demo (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(30) NOT NULL,
content VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
这里:
- id:留言编号。
- username:用户名。
- content:留言内容。
- created_at:创建时间。
32.2 插入数据
sql
INSERT INTO message_demo(username, content, created_at)
VALUES
('zhangsan', 'Hello MySQL', '2026-11-12 10:00:00'),
('lisi', '我正在学习MySQL', '2026-11-12 10:01:00'),
('wangwu', NULL, '2026-11-12 10:03:00');
32.3 查询留言内容和发布日期
sql
SELECT
username,
content,
DATE(created_at) AS publish_date
FROM message_demo;
32.4 查询每条留言的字符数
sql
SELECT
username,
content,
CHAR_LENGTH(content) AS content_length
FROM message_demo;
对于 content 为 NULL 的记录,CHAR_LENGTH 的结果也会是 NULL。
如果希望返回 0,可以写成:
sql
SELECT
username,
IFNULL(CHAR_LENGTH(content), 0) AS content_length
FROM message_demo;
32.5 查询包含 MySQL 的留言
sql
SELECT *
FROM message_demo
WHERE INSTR(content, 'MySQL') > 0;
这里只查询 content 中包含 MySQL 的记录。
32.6 为留言生成显示内容
sql
SELECT CONCAT(
username,
' 发布于 ',
DATE(created_at),
':',
IFNULL(content, '暂无内容')
) AS message_info
FROM message_demo;
结果类似:
text
zhangsan 发布于 2026-11-12:Hello MySQL
lisi 发布于 2026-11-12:我正在学习MySQL
wangwu 发布于 2026-11-12:暂无内容
这个案例同时使用了:
- CONCAT:字符串拼接。
- DATE:提取日期。
- IFNULL:处理空值。
它体现了 MySQL 函数嵌套使用的特点。
三十三、SQL 实战:统计字符串中逗号出现的次数
最后来看一道比较典型的字符串函数练习。
33.1 题目
给定字符串:
text
10,A,B
要求统计其中逗号:
text
,
出现的次数。
正确答案是:
text
2
如何使用 SQL 完成?
33.2 解题思路
我们可以利用:
sql
REPLACE()
将所有逗号删除。
原字符串:
text
10,A,B
删除逗号后:
text
10AB
然后比较删除前后的字符串长度。
原字符串长度:
text
6
删除逗号后长度:
text
4
因此:
6 − 4 = 2 6-4=2 6−4=2
也就得到了逗号出现的次数。
33.3 SQL 实现
sql
SELECT
LENGTH('10,A,B')
- LENGTH(REPLACE('10,A,B', ',', ''))
AS cnt;
结果:
text
+-----+
| cnt |
+-----+
| 2 |
+-----+
逐个解释:
第一步:
sql
LENGTH('10,A,B')
返回原始字符串字节数:
text
6
第二步:
sql
REPLACE('10,A,B', ',', '')
将逗号替换为空字符串:
text
10AB
第三步:
sql
LENGTH('10AB')
返回:
text
4
第四步:
text
6 - 4 = 2
因此得到最终结果。
33.4 更通用的思路
如果只是统计单个字符出现的次数,可以使用:
sql
SELECT
CHAR_LENGTH('10,A,B')
- CHAR_LENGTH(REPLACE('10,A,B', ',', ''))
AS cnt;
对于单个逗号字符,这种方法同样能够得到正确结果。
如果需要统计由多个字符组成的子字符串,通常还需要将长度差除以目标子字符串的字符长度。
例如,统计字符串中 abc 出现的次数:
sql
SELECT
(
CHAR_LENGTH('abc123abc456abc')
- CHAR_LENGTH(
REPLACE('abc123abc456abc', 'abc', '')
)
) / CHAR_LENGTH('abc') AS cnt;
结果:
text
3
这个思路可以应用在很多 SQL 字符串处理题中。
三十四、常见问题总结
34.1 NOW() 和 CURRENT_DATE() 有什么区别?
sql
NOW()
返回日期和时间。
sql
CURRENT_DATE()
只返回日期。
如果只需要年月日,可以使用 CURRENT_DATE。
如果需要记录完整操作时间,可以使用 NOW。
34.2 LENGTH 与 CHAR_LENGTH 有什么区别?
LENGTH 返回字节数。
CHAR_LENGTH 返回字符数。
例如,在 MySQL 的 utf8 字符集下:
sql
SELECT
LENGTH('中国'),
CHAR_LENGTH('中国');
通常得到:
text
6
2
34.3 SUBSTRING 为什么从 1 开始?
因为 MySQL 字符串函数通常使用从 1 开始的字符位置编号。
这与 C/C++ 数组从 0 开始的下标习惯不同。
34.4 CONCAT 为什么可能返回 NULL?
因为 CONCAT 的某个参数为 NULL 时,整个结果通常返回 NULL。
可以使用 IFNULL 为可能为空的参数提供替代值。
34.5 FORMAT 和 ROUND 有什么区别?
FORMAT 返回格式化字符串。
ROUND 主要用于数值舍入,结果仍然是数值类型。
需要继续计算时,不应该随意把 FORMAT 的字符串结果直接当成数值使用。
34.6 DATE_ADD 与 DATE_SUB 有什么区别?
DATE_ADD 用于增加时间间隔。
DATE_SUB 用于减去时间间隔。
例如:
sql
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY);
表示一天之后。
sql
SELECT DATE_SUB(NOW(), INTERVAL 1 DAY);
表示一天之前。
34.7 使用函数会修改原始数据吗?
如果只是执行:
sql
SELECT UCASE(name)
FROM string_demo;
不会修改表中的原始数据。
但如果执行:
sql
UPDATE string_demo
SET name = UCASE(name);
就会把转换后的值写入数据库。
所以,SELECT 负责产生查询结果,而 UPDATE 会修改实际记录。
34.8 MD5 可以用于用户密码吗?
不建议。
MD5 不适合直接保存现代系统的用户密码。
实际系统应使用专门的密码哈希算法,并按照对应算法的要求进行盐值和参数管理。
三十五、常用 MySQL 内置函数速查表
35.1 日期函数
| 函数 | 作用 |
|---|---|
| CURRENT_DATE() | 获取当前日期 |
| CURRENT_TIME() | 获取当前时间 |
| CURRENT_TIMESTAMP() | 获取当前日期时间 |
| NOW() | 获取当前日期时间 |
| DATE() | 提取日期部分 |
| DATE_ADD() | 日期加法 |
| DATE_SUB() | 日期减法 |
| DATEDIFF() | 日期天数差 |
35.2 字符串函数
| 函数 | 作用 |
|---|---|
| CHARSET() | 获取字符集名称 |
| CONCAT() | 拼接字符串 |
| INSTR() | 查找子串位置 |
| UCASE() | 转大写 |
| LCASE() | 转小写 |
| LEFT() | 截取左侧字符 |
| LENGTH() | 获取字节数 |
| CHAR_LENGTH() | 获取字符数 |
| REPLACE() | 替换字符串 |
| STRCMP() | 字符串比较 |
| SUBSTRING() | 截取子字符串 |
| LTRIM() | 删除左侧空格 |
| RTRIM() | 删除右侧空格 |
| TRIM() | 删除两侧空格 |
35.3 数学函数
| 函数 | 作用 |
|---|---|
| ABS() | 绝对值 |
| BIN() | 转二进制字符串 |
| HEX() | 转十六进制 |
| CONV() | 进制转换 |
| CEILING() | 向上取整 |
| FLOOR() | 向下取整 |
| FORMAT() | 数值格式化 |
| ROUND() | 数值舍入 |
| RAND() | 生成随机数 |
| MOD() | 求余数 |
35.4 其他函数
| 函数 | 作用 |
|---|---|
| USER() | 获取连接用户信息 |
| CURRENT_USER() | 获取当前权限身份 |
| DATABASE() | 获取当前数据库 |
| MD5() | 计算 MD5 摘要 |
| PASSWORD() | MySQL 5.7 中的旧密码函数 |
| IFNULL() | 处理 NULL 值 |
三十六、总结
通过本篇的学习,我们系统了解了 MySQL 中常见的内置函数,并通过多个 SQL 实验掌握了它们的基本使用方式。
主要可以分为四个部分。
第一,日期函数。
学习了:
sql
CURRENT_DATE()
CURRENT_TIME()
CURRENT_TIMESTAMP()
NOW()
DATE_ADD()
DATE_SUB()
DATEDIFF()
这些函数可以用于记录消息发布时间、计算到期日期,以及查询一定时间范围内的数据。
第二,字符串函数。
学习了:
sql
CONCAT()
LENGTH()
CHAR_LENGTH()
INSTR()
REPLACE()
SUBSTRING()
UCASE()
LCASE()
TRIM()
这些函数可以完成字符串拼接、截取、比较、替换和长度计算。
其中需要特别注意:
LENGTH 计算字节数,CHAR_LENGTH 计算字符数。
在处理中文字符串时,这个区别尤其重要。
第三,数学函数。
学习了:
sql
ABS()
CEILING()
FLOOR()
FORMAT()
RAND()
MOD()
BIN()
HEX()
CONV()
这些函数可以用于数值处理、格式化、随机数生成与进制转换。
第四,其他函数。
学习了:
sql
USER()
DATABASE()
MD5()
PASSWORD()
IFNULL()
理解了如何查看当前数据库环境、处理 NULL,以及哈希摘要函数的基本概念。
从实际后端开发角度来看,MySQL 内置函数的价值在于:
让数据库能够在查询和数据处理过程中直接完成常见计算,而不必把所有简单操作都放到应用程序中处理。
例如:
sql
SELECT
username,
CONCAT(
'留言内容:',
IFNULL(content, '暂无内容')
) AS message,
DATE(created_at) AS publish_date
FROM message_demo
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);
这条 SQL 同时使用:
- CONCAT:拼接字符串。
- IFNULL:处理空值。
- DATE:提取日期。
- DATE_SUB:计算日期范围。
- NOW:获取当前时间。
- WHERE:筛选记录。
它已经能够完成一个简单留言系统中的业务查询。
不过,并不是使用的函数越多越好。在真实项目中,还需要考虑 SQL 的可读性、索引使用情况以及数据库与应用程序之间的职责划分。
到这里,我们已经完成了 MySQL 内置函数的基础学习。