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

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 内置函数的基础学习。

相关推荐
吴名氏.2 小时前
Java转AI Agent教程(第十三周)混合检索与重排
java·数据库·人工智能·ai·ai agent
爱码少年2 小时前
Springboot下如何将CSV文件数据导入H2、Mysql数据库表
数据库·mysql·csv
2603_969694853 小时前
【JavaWeb学习记录】MyBatis核心知识点与实战笔记:从入门到动态SQL
笔记·sql·学习·mysql·mybatis·javaweb·学习方法
可乐ea3 小时前
智能体记忆该拆成几层:笔记、记忆表示与注入上下文
服务器·数据库·笔记·ai智能体·提示词工程·上下文工程·记忆系统
数据技术说4 小时前
在 KES AI 数据库上搭一条 NL2SQL 链路:语义、召回、权限各放哪
人工智能·sql·代码规范
唐墨1234 小时前
linux kernel 比较数据大小的宏定义
linux·算法
程序开发阿元5 小时前
密码不进工具:一个独立开发者的服务器凭据管理办法
linux·ssh
阿义有问题5 小时前
MySQL 迁移达梦全流程实战:DTS 七步图解 + 对象名全大写适配(附踩坑清单)
数据库
Go Work7 小时前
两个等值条件摆着,MySQL 偏要全表扫
经验分享·笔记