1. 函数的理解
1.1 什么是函数
C中有函数,Java中有方法,MySQL中就是函数
作用: 把经常使用的代码封装起来, 需要的时候直接调用即可
提高了代码效率
又提高了可维护性
SQL 中我们也可以使用函数对检索出来的数据进行函数操作,极大地提高 用户对数据库的管理效率
分类(按定义):
- 内置函数
系统内置的通用函数
- 自定义函数
根据自己的需要编写的
1.2 不同DBMS函数的差异
使用SQL常用 数据库软件(DBMS) 而非直接与语言打交道,而DBMS 之间的差异性很大,远大于同一个语言不同版本之间的差异
只有很少的函数是被 DBMS 同时支持的
比如,大多数 DBMS 使用(||)或者(+)来做拼接符,而在 MySQL 中的字符串拼接函数为concat()
大部分 DBMS 会有特定函数------采用 SQL 函数的代码可移植性很差
1.3 MySQL的内置函数及分类
- 实现的功能角度可以分为数值函数、字符串函数、日期和时间函数、流程控制函数、加密与解密函数、获取MySQL信息函数、聚合函数等
- 内置函数再分为两类: 单行函数 、聚合函数(或分组函数)

单行函数:
- 操作数据对象
- 接受参数返回一个结果
- 只对一行进行变换
- 每行返回一个结果
- 可以嵌套
- 参数可以是一列或一个值
2. 数值函数
2.1 基本函数
| 函数名 |
功能说明 |
ABS(x) |
返回 x 的绝对值 |
SIGN(x) |
返回 x 的符号 : 正数 → 1,负数 → -1,零 → 0 |
PI() |
返回圆周率 π 的近似值(≈ 3.141592653589793) |
CEIL(x) / CEILING(x) |
返回大于或等于 x 的最小整数(向上取整) |
FLOOR(x) |
返回小于或等于 x 的最大整数(向下取整) |
LEAST(e₁, e₂, e₃, ...) |
返回参数列表中的最小值 |
GREATEST(e₁, e₂, e₃, ...) |
返回参数列表中的最大值 |
MOD(x, y) |
返回 x 除以 y 的余数 注意: • 多数数据库中结果符号与被除数 x 相同 • 若 y = 0,通常返回 NULL 或报错 |
RAND() |
返回 [0, 1) 区间内的伪随机浮点数(含 0,不含 1)。无种子时每次调用结果不同 |
RAND(x) |
返回 [0, 1) 区间内的伪随机浮点数,x 作为种子; 相同种子产生相同序列(确定性随机)(eg:rand(1)和rand(1)每次产生的随机数都相同,和rand(2)每次产生的都不同) |
ROUND(x) |
对 x 四舍五入 到最接近的整数 (.5 向远离零方向舍入,即"银行家舍入"在部分系统中可能不同,需依具体数据库而定;多数 SQL 实现为"四舍五入") |
ROUND(x, y) |
对 x 四舍五入 到小数点后 y 位 ;若 y < 0,则对整数部分舍入(如 ROUND(123.456, -1) = 120) |
TRUNCATE(x, y) |
将 x 截断为小数点后 y 位 (直接截断,不四舍五入) y 可为负数 |
SQRT(x) |
返回 x 的平方根 若 x < 0,返回 NULL(或报错,取决于系统) |
|
|
- 单行函数可嵌套
eg:ROUND(TRUNCATE(x, y))
2.2 角度与弧度互换函数
| 函数 |
用法 |
| RADIANS(x) |
将角度转化为弧度,其中,参数 x 为角度值 |
| DEGREES(x) |
将弧度转化为角度,其中,参数 x 为弧度值 |
2.3 三角函数
| 函数名 |
原表"用法"描述 |
规范/准确解释 |
关键说明 |
| SIN(x) |
返回 x 的正弦值,其中参数 x 为弧度值 |
正弦函数:sin(x)\sin(x)sin(x),输入为弧度 |
最常用三角函数;x 必须是弧度(如 30° 需先 RADIANS(30)) |
| ASIN(x) |
返回 x 的反正弦值......若 x ∉ [-1,1],返回 NULL |
反正弦函数:arcsin(x)\arcsin(x)arcsin(x),定义域 [−1,1][-1, 1][−1,1],值域 [−π2,π2][-\frac{\pi}{2}, \frac{\pi}{2}][−2π,2π] |
输入超范围时行为因系统而异:• MySQL/PostgreSQL → NULL• SQL Server → 报错• Python (math.asin) → ValueError |
| COS(x) |
返回 x 的余弦值,x 为弧度值 |
余弦函数:cos(x)\cos(x)cos(x),输入为弧度 |
与 SIN 配合使用广泛(如单位圆、向量投影) |
| ACOS(x) |
返回 x 的反余弦值......若 x ∉ [-1,1],返回 NULL |
反余弦函数:arccos(x)\arccos(x)arccos(x),定义域 [−1,1][-1, 1][−1,1],值域 [0,π][0, \pi][0,π] |
同样要求输入 ∈ [-1,1];常用于计算夹角(如两点间方位角) |
| TAN(x) |
返回 x 的正切值,x 为弧度值 |
正切函数:tan(x)=sinxcosx\tan(x) = \frac{\sin x}{\cos x}tan(x)=cosxsinx,输入为弧度 |
在 x=π2+kπx = \frac{\pi}{2} + k\pix=2π+kπ 处无定义(趋于无穷);实际中可能返回极大值或报错 |
| ATAN(x) |
返回 x 的反正切值 |
反正切函数:arctan(x)\arctan(x)arctan(x),定义域 R\mathbb{R}R,值域 (−π2,π2)(-\frac{\pi}{2}, \frac{\pi}{2})(−2π,2π) |
安全函数:任意实数输入均有效;常用于由斜率求角度 |
| ATAN2(m, n) |
返回两个参数的反正切值 |
二参数反正切:atan2(y,x)\operatorname{atan2}(y, x)atan2(y,x),返回点 (x,y)(x, y)(x,y) 与原点连线和 x 轴正方向的夹角(含象限信息) |
重要补充 :• 参数顺序通常是 ATAN2(y, x) (注意:您表中写的是 ATAN2(m,n),但标准是 y 在前、x 在后)• 值域:(−π,π](-\pi, \pi](−π,π],可正确区分四个象限• 例如:ATAN2(1, 1) → π/4;ATAN2(-1, -1) → -3π/4(或 5π/4,依实现) |
| COT(x) |
返回 x 的余切值,x 为弧度值 |
余切函数:cot(x)=1tan(x)=cosxsinx\cot(x) = \frac{1}{\tan(x)} = \frac{\cos x}{\sin x}cot(x)=tan(x)1=sinxcosx |
注意:• 多数数据库不直接支持 COT() (如 MySQL 8.0+ 无内置,SQL Server 无,PostgreSQL 无)• 通常需手动实现:1 / TAN(x) 或 COS(x)/SIN(x)• 在 x=kπx = k\pix=kπ 处无定义(分母为 0) |
2.4 指数与对数
| 函数名 |
原表"用法"描述 |
规范解释与关键细节 |
POW(x, y) / POWER(x, y) |
返回 x 的 y 次方 |
• 两者是同义函数(MySQL/SQL Server 中 POWER 更常用;PostgreSQL 支持 POWER 和 ^ 运算符) • 支持负指数:POW(2, -3) = 1/8 = 0.125 • 特殊情况: - x = 0, y > 0 → 0 - x = 0, y = 0 → 通常返回 1 (数学争议,但多数系统定义为 1) - x = 0, y < 0 → 报错或返回 NULL (除零错误) - x < 0, y 非整数 → 可能返回 NULL 或复数错误(如 POW(-2, 0.5) 是虚数,实数域无定义) |
EXP(X) |
返回 e 的 X 次方,e ≈ 2.71828... |
• 即自然指数函数:exp(x)=ex\exp(x) = e^xexp(x)=ex• 定义域:全体实数 ℝ • 值域:(0,+∞)(0, +\infty)(0,+∞) • 与 LN(X) 互为反函数: EXP(LN(x)) = x(当 x>0x > 0x>0) LN(EXP(x)) = x(对所有实数 x 成立) |
LN(X) / LOG(X) |
返回以 e 为底的 X 的对数;X ≤ 0 时返回 NULL |
• LN(X) 是标准写法(MySQL、PostgreSQL、Oracle) • LOG(X) 在 MySQL 中等价于 LN(X) ;但在 SQL Server / Oracle 中,LOG(X) 默认是 LOG10(X) (重要差异!) • 定义域:X>0X > 0X>0;若 X≤0X \leq 0X≤0,行为: - MySQL/PostgreSQL → NULL - SQL Server → 报错(Invalid floating point operation) - Python (math.log) → ValueError |
LOG10(X) |
返回以 10 为底的 X 的对数;X ≤ 0 时返回 NULL |
• 常用在科学计算、dB 计算、数量级分析中 • 与 LOG(X) 区分:明确指定底数为 10 • 同样要求 X>0X > 0X>0,否则返回 NULL 或报错 |
LOG2(X) |
返回以 2 为底的 X 的对数;X ≤ 0 时返回 NULL |
• 广泛用于计算机科学:比特位数、二叉树高度、信息熵等 • 例如:LOG2(8) = 3,LOG2(1024) = 10• 支持情况: - MySQL 8.0+ ✔️ - PostgreSQL ✔️(log(2, x) 或 log2(x)) - SQL Server ❌(需用 LOG(x)/LOG(2) 替代) - Oracle ✔️(LOG(2, x)) |
2.5 进制间的转换
| 函数名 |
原表"用法"描述 |
规范解释与重要说明 |
BIN(x) |
返回 x 的二进制编码 |
• 将十进制整数 x 转换为二进制字符串(不含前缀) • 例如:BIN(10) → '1010' • 仅支持非负整数;若 x < 0: - MySQL:返回带符号的补码形式(如 BIN(-1) → '11111111111111111111111111111111',32位) - 其他系统(如 SQLite)可能报错或返回 NULL • 输出为字符串类型,非数值 |
HEX(x) |
返回 x 的十六进制编码 |
• 将十进制整数 x 转为十六进制小写字符串(无 0x 前缀) • 例如:HEX(255) → 'ff';HEX(10) → 'a' • 同样要求 x 为整数;负数处理类似 BIN()(MySQL 返回补码) • 常用于颜色码、内存地址、哈希值显示等 |
OCT(x) |
返回 x 的八进制编码 |
• 将十进制整数 x 转为八进制字符串(无前缀) • 例如:OCT(10) → '12'(因 1010=1281010=128 ) • 应用较少,但在 Unix 权限(如 chmod 755)场景中有意义 |
CONV(x, f1, f2) |
返回 f1 进制数变成 f2 进制数 |
• 通用进制转换函数: CONV(str_or_num, from_base, to_base) • 参数说明: - x:可为字符串或数字(若为字符串,需是合法 f1 进制表示) - f1:源进制(2--36) - f2:目标进制(2--36) • 示例: - CONV('A', 16, 10) → '10'(十六进制 A → 十进制 10) - CONV(10, 10, 2) → '1010'(十进制 10 → 二进制) - CONV('1010', 2, 16) → 'A' • 注意: - 若输入非法(如 CONV('G', 16, 10)),通常返回 NULL - 支持字母 A--Z 表示 10--35(大小写不敏感) - MySQL 特有函数;PostgreSQL/SQL Server 等需用自定义逻辑实现 |
3. 字符串函数
3.1 函数分类与逐项解析
3.1.1 基础信息获取类
| 函数 |
说明 |
关键细节 |
ASCII(s) |
返回字符串 s 第一个字符的 ASCII 码 |
• 仅取首字符 • 非 ASCII 字符(如中文)返回其 UTF-8 编码首字节(MySQL 中) • 例:ASCII('A')=65, ASCII('中')=228(UTF-8 首字节) |
CHAR_LENGTH(s) |
返回字符串 s 的字符数(Unicode 字符个数) |
• 与 CHARACTER_LENGTH(s) 同义 • 区别于 LENGTH(s): - CHAR_LENGTH('café') = 4(4 个字符) - LENGTH('café') = 5(UTF-8 下 'é' 占 2 字节) |
LENGTH(s) |
返回字符串 s 的字节数 |
• 依赖字符集(utf8mb4 下中文占 4 字节) • 用于计算存储空间或网络传输大小 |
3.1.2 字符串拼接与构造类
| 函数 |
说明 |
补充说明 |
CONCAT(s1, s2, ..., sn) |
连接多个字符串 |
• 若任一参数为 NULL,结果为 NULL• MySQL 中不可简写为 s1 + s2 + 是算术加法,字符串拼接必须用 CONCAT 或 ` |
CONCAT_WS(x, s1, s2, ...) |
用分隔符 x 连接字符串 |
• W ith S eparator • 自动跳过 NULL 参数(但保留空字符串 '') • 例:CONCAT_WS(',', 'a', NULL, 'c') → 'a,c' |
3.1.3 字符串替换与修改类
| 函数 |
说明 |
注意事项 |
INSERT(str, idx, len, replacestr) |
从 idx 位置起,替换 len 个字符为 replacestr |
• 位置从 1 开始 (MySQL 特性) • 若 idx > CHAR_LENGTH(str),则在末尾追加 • 若 len=0,相当于插入 |
REPLACE(str, a, b) |
将 str 中所有 a 替换为 b |
• 全局替换,非正则 • 例:REPLACE('hello world', 'l', 'X') → 'heXXo worXd' |
UPPER(s) / UCASE(s) |
转大写 |
• 两者等价;UCASE 是旧版兼容写法 |
LOWER(s) / LCASE(s) |
转小写 |
• 同上 |
3.1.4 子字符串提取类
| 函数 |
说明 |
LEFT(str, n) |
取最左 n 个字符 |
RIGHT(str, n) |
取最右 n 个字符 |
SUBSTR(s, index, len) |
从 index 起取 len 个字符 |
LPAD(str, len, pad) |
用字符串pad对str最左边进行填充,直到str的长度为len个字符 |
RPAD(str ,len, pad) |
用字符串pad对str最右边进行填充,直到str的长度为len个字符 |
示例:
SUBSTR('abcdef', 2, 3) → 'bcd'
SUBSTR('abcdef', -3) → 'def'(负索引从右往左数)
3.1.5 空白字符处理类
| 函数 |
作用 |
差异点 |
LTRIM(s) |
去左空格 |
仅去空格(' '),不去制表符 \t 等(除非用 TRIM(LEADING ' ' FROM s)) |
RTRIM(s) |
去右空格 |
同上 |
TRIM(s) |
去左右空格 |
标准 SQL 支持更灵活:TRIM(BOTH 'x' FROM s) |
TRIM(s1 FROM s) |
去掉 s 开头和结尾的 s1 |
• 例:TRIM('xy' FROM 'xyhelloxxy') → 'hellox' |
TRIM(LEADING s1 FROM s) |
仅去开头的 s1 |
MySQL 支持 |
TRIM(TRAILING s1 FROM s) |
仅去结尾的 s1 |
MySQL 支持 |
SPACE(n) |
返回 n 个空格组成的字符串 |
• 例:CONCAT('a', SPACE(3), 'b') → 'a b' |
3.1.6 位置查找与比较类
| 函数 |
说明 |
注意事项 |
LOCATE(substr, str) |
返回 substr 在 str 中首次出现的位置(从 1 开始) |
• 找不到返回 0 • 等价于 POSITION(substr IN str) 和 INSTR(str, substr) |
POSITION(substr IN str) |
同 LOCATE |
标准 SQL 写法 |
INSTR(str, substr) |
同 LOCATE |
MySQL 特有(参数顺序相反!)→ INSTR(str, substr) vs LOCATE(substr, str) |
ELT(m, s1, s2, ..., sn) |
返回第 m 个参数 |
• 类似编程语言的"数组索引" • m < 1 或 m > n → NULL • 例:ELT(2, 'a','b','c') → 'b' |
FIELD(s, s1, s2, ..., sn) |
返回 s 在列表中第一次出现的位置 |
• 找不到返回 0 • 例:FIELD('mm', 'mm','hello','msm') → 1 • 常用于自定义排序(如 ORDER BY FIELD(id, 3,1,2)) |
FIND_IN_SET(s1, s2) |
查找 s1 在以逗号分隔的字符串 s2 中的位置 |
• s2 必须是 ',' 分隔的列表(不能含空格) • 例:FIND_IN_SET('hello', 'mm,hello,msm,amma') → 2 •不支持通配符,不适用于 JSON 数组 |
FIND_IN_SET 陷阱:
'a' 在 'ab' 中找不到(必须完全匹配)
' a '(带空格)在 'a,b' 中也找不到
3.1.7 其他实用函数
| 函数 |
说明 |
应用场景 |
REPEAT(str, n) |
重复 str n 次 |
• 生成固定长度填充:REPEAT('0', 5-CHAR_LENGTH(id)) + id → 补零 |
STRCMP(s1, s2) |
比较两个字符串的 ASCII 值大小 |
• 返回:-1(s1 < s2)、0(相等)、1(s1 > s2) • 可用于 ORDER BY STRCMP(col, 'target') 实现"目标值置顶" |
NULLIF(value1, value2) |
若 value1 = value2 则返回 NULL,否则返回 value1 |
• 防止除零:SELECT num / NULLIF(denom, 0) • 等价于 CASE WHEN value1 = value2 THEN NULL ELSE value1 END |
REVERSE(s) |
返回s反转后的字符串 |
- |
3.2 关键注意事项
注意:MySQL 中,字符串的位置是从 1 开始的。
3.3 典型应用场景举例
3.3.1 补零 ID 格式化
sql
复制代码
-- 将数字 ID 补成 6 位:000123
SELECT LPAD(id, 6, '0') AS formatted_id FROM users;
-- 或用 REPEAT:
SELECT REPEAT('0', 6 - CHAR_LENGTH(id)) + id AS formatted_id;
3.3.2 自定义排序(按指定顺序)
sql
复制代码
SELECT * FROM products
ORDER BY FIELD(category, 'Electronics', 'Books', 'Clothing');
3.3.3 安全除法(防除零)
sql
复制代码
SELECT amount / NULLIF(quantity, 0) AS unit_price FROM sales;
3.3.4 提取文件扩展名
sql
复制代码
-- 假设 filename = 'report.pdf'
SELECT SUBSTRING_INDEX(filename, '.', -1) AS ext; -- 'pdf'
-- (注:`SUBSTRING_INDEX` 未在表中列出,但常用)
4. 日期和时间函数
4.1 获取日期、时间
| 函数(写法) |
用法 |
规范解释与重要说明 |
CURDATE() , CURRENT_DATE() |
返回当前日期,只包含年、月、日 |
• 返回 DATE 类型值(格式如 '2024-06-15') • 两者完全等价(CURRENT_DATE 是 SQL 标准写法,CURDATE 是 MySQL 特有别名) • 不带时区信息,基于服务器系统时间 |
CURTIME() , CURRENT_TIME() |
返回当前时间,只包含时、分、秒 |
• 返回 TIME 类型值(格式如 '14:30:45') • 同样两者等价;CURRENT_TIME 是标准,CURTIME 是 MySQL 别名 • 可选精度:CURTIME(6) → '14:30:45.123456'(微秒级) |
NOW() SYSDATE() CURRENT_TIMESTAMP() LOCALTIME() LOCALTIMESTAMP() |
返回当前系统日期和时间 |
这些函数看似相同,但行为有关键差异: NOW(): - 返回 语句开始执行时的时间(固定值) - 在同一语句内多次调用结果相同(用于事务一致性) SYSDATE(): - 返回 函数被调用时的实时时间(动态值) - 同一语句内多次调用可能不同(如 SELECT SYSDATE(), SLEEP(2), SYSDATE()) CURRENT_TIMESTAMP(), LOCALTIME(), LOCALTIMESTAMP(): - 在 MySQL 中 等价于 NOW()(即语句开始时间) - LOCAL* 是 SQL 标准写法,兼容性更好 示例: sql<br>SELECT NOW(), SYSDATE(), SLEEP(2), NOW(), SYSDATE();<br>-- 结果:t, t+2s, t, t+2s (t 为语句开始时间)<br> |
UTC_DATE() |
返回 UTC(世界标准时间)日期 |
• 返回当前 UTC 日期(DATE 类型) • 不受服务器时区影响 • 例:服务器在东八区(北京时间),CURDATE() = '2024-06-15',UTC_DATE() 可能是 '2024-06-14'(若此时为 00:30 北京时间) |
UTC_TIME() |
返回 UTC(世界标准时间)时间 |
• 返回当前 UTC 时间(TIME 类型) • 与 UTC_DATE() 配合可得完整 UTC 时间戳: CONCAT(UTC_DATE(), ' ', UTC_TIME()) |
4.2 日期与时间戳的转换
| 函数 |
用法描述 |
规范解释与关键细节 |
UNIX_TIMESTAMP() |
以 UNIX 时间戳 的形式返回当前时间 。 示例:SELECT UNIX_TIMESTAMP() → 1634348884 |
• 返回 自 1970-01-01 00:00:00 UTC 起的秒数(整数类型) • 注意:MySQL 中默认返回 秒级(非毫秒);若需微秒级,可用 UNIX_TIMESTAMP() * 1000 + MICROSECOND(NOW(6)) / 1000 • 时区影响: - 函数返回的是 UTC 时间对应的秒数,与服务器本地时区无关 - 即使服务器设为 +8:00,UNIX_TIMESTAMP() 仍基于 UTC 计算 • 示例: UNIX_TIMESTAMP('2021-10-15 12:00:00') → 1634270400(该时间点的 UTC 秒数) |
UNIX_TIMESTAMP(date) |
将时间 date 以 UNIX 时间戳形式返回 |
• 参数 date 可为: - 字符串(如 '2021-10-15', '2021-10-15 12:00:00') - DATE / DATETIME / TIMESTAMP 类型值 • 解析规则: - 若只传日期(无时间),默认视为 UTC 时间的 00:00:00 → UNIX_TIMESTAMP('2021-10-15') = 1634256000(即 2021-10-15 00:00:00 UTC) - 若传带时区的字符串(如 '2021-10-15 12:00:00+08:00'),MySQL 不支持直接解析时区偏移!会当作本地时间处理(依赖会话时区)→ 易出错! • 安全做法:统一使用 UTC 时间字符串输入 |
FROM_UNIXTIME(timestamp) |
将 UNIX 时间戳转换为普通格式的时间 |
• 输入:整数(秒级 UNIX 时间戳) • 输出:DATETIME 类型(格式如 '2021-10-15 12:00:00') • 时区行为: - 结果基于会话时区(@@session.time_zone)! |
4.3 获取月份、星期、星期数、天数等函数
| 函数 |
用法 |
解释 + 关键细节 |
YEAR(date) / MONTH(date) / DAY(date) |
返回具体的日期值 |
• 提取年、月、日 的数值(整数) • 例:YEAR('2024-06-15') = 2024,MONTH('2024-06-15') = 6,DAY('2024-06-15') = 15 • 等价于 YEAR(), MONTH(), DAYOFMONTH()(注意:DAY() = DAYOFMONTH()) |
HOUR(time) / MINUTE(time) / SECOND(time) |
返回具体的时间值 |
• 提取时、分、秒 的数值 • 例:HOUR('14:30:45') = 14 • 支持 DATETIME/TIMESTAMP 类型输入 |
MONTHNAME(date) |
返回月份:January, ... |
• 返回英文全称(受 lc_time_names 系统变量影响) • 可通过 SET lc_time_names = 'zh_CN' 改为中文(需对应语言包) • 例:MONTHNAME('2024-06-15') = 'June' |
DAYNAME(date) |
返回星期几:MONDAY, TUESDAY...SUNDAY |
• 返回英文全称大写(如 'SATURDAY') • 同样受 lc_time_names 影响,可本地化 • 注意:不是数字!是字符串 |
WEEKDAY(date) |
返回周几,注意:周1是0,周2是1,... 周日是6 |
MySQL 特有规则: • WEEKDAY():周一 = 0,周日 = 6 • 例:WEEKDAY('2024-06-15')(周六)→ 5 • 与 DAYOFWEEK() 完全相反!极易混淆 |
QUARTER(date) |
返回日期对应的季度,范围为 1~4 |
• 1月--3月 → 1;4月--6月 → 2;7月--9月 → 3;10月--12月 → 4 • 例:QUARTER('2024-05-20') = 2 |
WEEK(date), WEEKOFYEAR(date) |
返回一年中的第几周 |
• 两者等价(WEEKOFYEAR 是别名) • 但 周的定义取决于模式(mode)!默认模式 0: - 第一周是包含 1 月 1 日的那一周 - 周日为每周第一天(与 WEEKDAY 冲突!) • 可指定模式:WEEK(date, mode),常见: - mode=1:周一为每周第一天,且第一周必须有 4 天以上在本年 → ISO 标准周 - mode=3:同上,但返回 0~53 • 例: WEEK('2024-01-01') → 1(默认模式) WEEK('2024-01-01', 1) → 1(ISO 周) WEEK('2023-12-31', 1) → 52(2023 年第 52 周) |
DAYOFYEAR(date) |
返回日期是一年中的第几天 |
• 范围 1~366(闰年) • 例:DAYOFYEAR('2024-01-01') = 1,DAYOFYEAR('2024-12-31') = 366 |
DAYOFMONTH(date) |
返回日期位于所在月份的第几天 |
• 即 DAY(date) 的正式名称 • 例:DAYOFMONTH('2024-06-15') = 15 |
DAYOFWEEK(date) |
返回周几 注意: 周日是1,周一2,... 周六是7 |
这是另一套编号体系: • DAYOFWEEK():周日 = 1,周一 = 2,...,周六 = 7 • 与 WEEKDAY() 完全相反! • 例:DAYOFWEEK('2024-06-15')(周六)→ 7 • 这是 SQL 标准行为(PostgreSQL/SQL Server 也如此) |
4.4 日期的操作函数
| 函数 |
用法 |
EXTRACT(type FROM date) |
返回指定日期中的特定部分,type指定返回的值 |
| type的取值与含义: |
|
type 取值 |
含义 |
示例(输入 '2024-06-15 14:30:45.123456') |
注意事项 |
MICROSECOND |
毫秒数(0~999999) |
123456 |
精度最高 |
SECOND |
秒数(0~59) |
45 |
--- |
MINUTE |
分钟数(0~59) |
30 |
--- |
HOUR |
小时数(0~23) |
14 |
--- |
DAY |
月内天数(1~31) |
15 |
= DAYOFMONTH() |
WEEK |
年内第几周(默认 mode 0) |
24 |
行为依赖 default_week_format,建议显式用 WEEK() |
MONTH |
月份(1~12) |
6 |
= MONTH() |
QUARTER |
季度(1~4) |
2 |
= QUARTER() |
YEAR |
年份(4位) |
2024 |
= YEAR() |
SECOND_MICROSECOND |
秒 + 毫秒(如 45.123456) |
45.123456 |
MySQL 8.0+ 返回 DECIMAL;旧版返回字符串 |
MINUTE_MICROSECOND |
分 + 毫秒(如 30.123456) |
30.123456 |
同上 |
MINUTE_SECOND |
分 + 秒(如 30.45) |
30.45 |
注意:不是 3045!是小数形式 |
HOUR_MICROSECOND |
时 + 毫秒(如 14.000123) |
14.000123 |
--- |
HOUR_SECOND |
时 + 秒(如 14.45) |
14.45 |
--- |
HOUR_MINUTE |
时 + 分(如 14.30) |
14.30 |
易错:不是 '14:30' 字符串(MySQL 8.0+ 是 DECIMAL) |
DAY_MICROSECOND |
天 + 毫秒(如 15.000123) |
15.000123 |
--- |
DAY_SECOND |
天 + 秒(如 15.45) |
15.45 |
--- |
DAY_MINUTE |
天 + 分(如 15.30) |
15.30 |
--- |
DAY_HOUR |
天 + 小时(如 15.14) |
15.14 |
--- |
YEAR_MONTH |
年 + 月(如 2024.06) |
2024.06 |
实际返回 2024.06(DECIMAL),可用于按年月分组 |
4.5 时间和秒钟转换的函数
| 函数 |
原表"用法"描述 |
规范解释 + 关键补充 |
TIME_TO_SEC(time) |
将 time 转化为秒并返回结果值。 公式:小时 × 3600 + 分钟 × 60 + 秒 时间 转 秒 |
• 输入类型:TIME, DATETIME, TIMESTAMP 或字符串(如 '14:30:45', '2 14:30:45') • 支持"天数"前缀!例如: TIME_TO_SEC('2 14:30:45') → 2×86400 + 14×3600 + 30×60 + 45 = 225045 • 返回值类型:BIGINT(整数) • 注意:若输入为负时间(如 '-01:30:00'),返回负值(-5400) • 对 DATETIME 类型:仅提取时间部分,忽略日期! 例:TIME_TO_SEC('2024-06-15 14:30:45') = 52245(=14×3600+30×60+45) |
SEC_TO_TIME(seconds) |
将 seconds 描述转化为包含小时、分钟和秒的时间 秒 转 时间 |
• 输入:整数(可正可负) • 输出类型:TIME(格式如 '14:30:45' 或 '-01:30:00') • 支持大数值(最大约 838:59:59,即 838 小时上限) • 重要限制: MySQL 的 TIME 类型范围是 -838:59:59 到 838:59:59 → 若 seconds > 838*3600+59*60+59 = 3020399,会截断或报错(取决于 SQL 模式) • 示例: SEC_TO_TIME(52245) → '14:30:45' SEC_TO_TIME(-5400) → '-01:30:00' |
4.6 计算日期和时间的函数
4.6.1 第一组
| 函数 |
用法 |
DATE_ADD(datetime, INTERVAL expr type) , ADDDATE(date,INTERVAL expr type) |
返回与给定日期时间相差INTERVAL时间段的日期时间 |
DATE_SUB(date,INTERVAL expr type), SUBDATE(date,INTERVAL expr type) |
返回与date相差INTERVAL时间间隔的日期 |
- 注: add加,sub减,但仅用add通过正负也可以实现加减
type 的取值:
unit 取值 |
含义 |
示例 |
注意事项 |
HOUR |
小时 |
INTERVAL 2 HOUR |
支持负数 |
MINUTE |
分钟 |
INTERVAL 30 MINUTE |
--- |
SECOND |
秒 |
INTERVAL 45 SECOND |
--- |
YEAR |
年 |
INTERVAL 5 YEAR |
跳过闰年问题(2020+5=2025) |
MONTH |
月 |
INTERVAL 1 MONTH |
最常用也最易错:见上文智能进位 |
DAY |
日 |
INTERVAL 7 DAY |
等价于 WEEK?不!7 DAY = 1周,但 WEEK 单位是 7 天 |
YEAR_MONTH |
年+月 |
INTERVAL 2 YEAR 3 MONTH |
支持组合(见下文) |
DAY_HOUR |
日+小时 |
INTERVAL 1 DAY 2 HOUR |
支持多单位组合! |
DAY_MINUTE |
日+分 |
INTERVAL 1 DAY 30 MINUTE |
--- |
DAY_SECOND |
日+秒 |
INTERVAL 1 DAY 10 SECOND |
--- |
HOUR_MINUTE |
时+分 |
INTERVAL 2 HOUR 15 MINUTE |
--- |
HOUR_SECOND |
时+秒 |
INTERVAL 1 HOUR 30 SECOND |
--- |
MINUTE_SECOND |
分+秒 |
INTERVAL 5 MINUTE 45 SECOND |
--- |
4.6.2 第二组
| 函数 |
用法 |
本质 |
实战建议 |
ADDTIME(time1, time2) |
time1 + time2 |
时间相加(非日期) |
适合纯时间累加(如班次时长) |
SUBTIME(time1, time2) |
time1 - time2 |
时间相减 |
注意:结果可为负('-01:30:00') |
DATEDIFF(date1, date2) |
date1 - date2(天数) |
仅比较日期部分,忽略时间 |
快速计算"相差几天",如会员到期提醒 |
TIMEDIFF(time1, time2) |
time1 - time2(时间差) |
返回 TIME 类型(如 '02:15:30') |
计算会话时长、响应时间 |
FROM_DAYS(N) |
从 0000-01-01 起第 N 天的日期 |
N=1 → 0000-01-01;N=738000 → 2020-01-01 |
用于日志序列号转日期(罕见) |
TO_DAYS(date) |
返回 date 距离 0000-01-01 的天数 |
与 FROM_DAYS 互为反函数 |
性能优化:用 TO_DAYS 做范围查询(但现代索引更推荐 DATE 直接比较) |
LAST_DAY(date) |
返回 date 所在月份的最后一天 |
LAST_DAY('2024-06-15') = '2024-06-30' |
生成报表截止日、财务月结日 |
MAKEDATE(year, n) |
第 n 天的日期(n=1 → year-01-01) |
MAKEDATE(2024, 172) = '2024-06-20' |
用于按"年内第几天"生成日期 |
MAKETIME(hour, min, sec) |
组合时间 |
MAKETIME(14,30,45) = '14:30:45' |
构造动态时间值 |
PERIOD_ADD(time, n) |
time(格式 YYMM 或 YYYYMM)加 n 个月 |
PERIOD_ADD(202406, 3) = 202409 |
用于金融/账期管理(如 202406 表示2024年6月) |
4.7 日期的格式化与解析
| 函数 |
输入类型 |
输出类型 |
核心用途 |
DATE_FORMAT(date, fmt) |
DATE / DATETIME / TIMESTAMP |
VARCHAR |
按照字符串fmt格式化日期date值 data->str |
TIME_FORMAT(time, fmt) |
TIME / DATETIME |
VARCHAR |
按照字符串fmt格式化时间time值 time->str |
GET_FORMAT(date_type, format_type) |
字符串参数 |
VARCHAR |
返回日期字符串的显示格式 ->str 按指定格式转换 |
STR_TO_DATE(str, fmt) |
VARCHAR + 格式模板 |
DATE / DATETIME |
按照字符串fmt对str进行解析,解析为一个日期 str->date |
| 上述非GET_FORMAT 函数中fmt参数常用的格式符: |
|
|
|
| 格式符 |
正确含义 |
示例(输入 2024-06-15 14:30:45) |
%Y |
4位年份 |
2024 |
%y |
2位年份 |
24 |
%M |
全称月份英文(January) |
June |
%b |
缩写月份(Jan, Feb) |
Jun |
%m |
2位数字月份 |
06 |
%c |
1位数字月份(1~12) |
6 |
%D |
英文后缀日(1st, 2nd) |
15th |
%d |
2位数字日 |
15 |
%e |
1位数字日(1~31) |
15 |
%H |
24小时制小时(00~23) |
14 |
%h 或 %I |
12小时制小时(01~12) |
02 |
%k |
24小时制小时(0~23,无前导零) |
14 |
%l |
12小时制小时(1~12,无前导零) |
2 |
%i |
2位分钟 |
30 |
%s |
2位秒数 |
45 |
%f |
微秒(6位) |
000000(若无微秒则补零) |
%W |
全称星期名(Sunday) |
Saturday |
%a |
缩写星期名(Sun) |
Sat |
%w |
数字星期(0=周日, 6=周六) |
6 |
%j |
年内第几天(001~366) |
167 |
%U |
年内第几周(周日为每周第一天) |
24 |
%u |
年内第几周(周一为每周第一天,ISO标准) |
24 |
%T |
HH:MM:SS(24小时) |
14:30:45 |
%r |
hh:mm:ss AM/PM(12小时) |
02:30:45 PM |
%p |
AM 或 PM |
PM |
| GET_FORMAT函数中date_type和format_type参数取值如下: |
|
|
| 日期类型 |
格式化类型 |
返回的格式化字符串 |
| DATE |
USA |
%m.%d.%Y |
| DATE |
JIS |
%Y-%m-%d |
| DATE |
ISO |
%Y-%m-%d |
| DATE |
EUR |
%d.%m.%Y |
| DATE |
INTERNAL |
%Y%m%d |
| TIME |
USA |
%h:%i:%s %p |
| TIME |
JIS |
%H:%i:%s |
| TIME |
ISO |
%H:%i:%s |
| TIME |
EUR |
%H:%i:%s |
| TIME |
INTERNAL |
%H%i%s |
| DATETIME |
USA |
%Y-%m-%d %H:%i:%s |
| DATETIME |
JIS |
%Y-%m-%d %H:%i:%s |
| DATETIME |
ISO |
%Y-%m-%d %H:%i:%s |
| DATETIME |
EUR |
%Y-%m-%d %H:%i:%s |
| DATETIME |
INTERNAL |
%Y%m%d%H%i%s |
5. 流程控制函数
- 根据不同的条件,执行不同的处理流程,可以在SQL语句中实现不同的条件选择
- 主要包括IF()、IFNULL()和CASE()函数
| 函数 |
用法 |
IF(value, value1, value2) |
如果 value 的值为 TRUE,返回 value1,否则返回 value2 |
IFNULL(value1, value2) |
如果 value1 不为 NULL,返回 value1,否则返回 value2 |
CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 ... [ELSE 结果n] END |
相当于 Java 的 if...else if...else... |
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 ... [ELSE 值n] END |
相当于 Java 的 switch...case... |
IF(value, value1, value2)
sql
复制代码
mysql> SELECT
-> last_name,
-> salary,
-> IF(salary >= 6000,'高工资','低工资') 'details'
-> FROM employees;
+-------------+----------+---------+
| last_name | salary | details |
+-------------+----------+---------+
| King | 24000.00 | 高工资 |
| Kochhar | 17000.00 | 高工资 |
| De Haan | 17000.00 | 高工资 |
| Hunold | 9000.00 | 高工资 |
| Ernst | 6000.00 | 高工资 |
| Austin | 4800.00 | 低工资 |
| Pataballa | 4800.00 | 低工资 |
| ... | ... | ... |
+-------------+----------+---------+
(省略100条记录)
107 rows in set (0.01 sec)
sql
复制代码
mysql> SELECT
-> last_name,
-> commission_pct,
-> IFNULL(commission_pct,0) 'details'
-> FROM
-> employees;
+-------------+----------------+---------+
| last_name | commission_pct | details |
+-------------+----------------+---------+
| King | NULL | 0.00 |
| Kochhar | NULL | 0.00 |
| De Haan | NULL | 0.00 |
| Hunold | NULL | 0.00 |
| Ernst | NULL | 0.00 |
| ... | ... | ... |
| Hutton | 0.25 | 0.25 |
| Taylor | 0.20 | 0.20 |
| Livingston | 0.20 | 0.20 |
| Grant | 0.15 | 0.15 |
| Johnson | 0.10 | 0.10 |
| ... | ... | ... |
| Baer | NULL | 0.00 |
| Higgins | NULL | 0.00 |
| Gietz | NULL | 0.00 |
+-------------+----------------+---------+
(...为省略记录)
107 rows in set (0.00 sec)
CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 ... [ELSE 结果n] END
sql
复制代码
mysql> SELECT
-> last_name,
-> CASE
-> WHEN salary >= 10000 THEN
-> '高工资'
-> WHEN salary >= 5000 THEN
-> '中工资'
-> ELSE '低工资'
-> END 'details'
-> FROM
-> employees;
+-------------+---------+
| last_name | details |
+-------------+---------+
| King | 高工资 |
| Kochhar | 高工资 |
| De Haan | 高工资 |
| Hunold | 中工资 |
| Ernst | 中工资 |
| Austin | 低工资 |
| ... | ... |
+-------------+---------+
(...为省略记录)
107 rows in set (0.00 sec)
注:若没有else,则else的内容输出NULL
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 ... [ELSE 值n] END
sql
复制代码
mysql> SELECT
-> employee_id,
-> last_name,
-> department_id,
-> CASE department_id
-> WHEN 10 THEN salary * 1.1
-> WHEN 20 THEN salary * 1.2
-> WHEN 30 THEN salary * 1.3
-> ELSE salary * 1.4
-> END 'details'
-> FROM employees;
+-------------+-------------+---------------+----------+
| employee_id | last_name | department_id | details |
+-------------+-------------+---------------+----------+
| 100 | King | 90 | 33600.00 |
| 101 | Kochhar | 90 | 23800.00 |
| 102 | De Haan | 90 | 23800.00 |
| 103 | Hunold | 60 | 12600.00 |
| 104 | Ernst | 60 | 8400.00 |
| 105 | Austin | 60 | 6720.00 |
| 106 | Pataballa | 60 | 6720.00 |
| ...| ... | ... | ... |
+-------------+-------------+---------------+----------+
(...为省略记录)
107 rows in set (0.00 sec)
Q&A:
Q:为什么没有循环?
A:sql自带循环,不用写
6. 加密与解密函数
- 加密与解密函数主要用于对数据库中的数据进行加密和解密处理,以防止数据被他人窃取
- 这些函数在保证数据库安全时非常有用
| 函数 |
用法 |
PASSWORD(str) |
返回字符串 str 的加密版本,41 位长的字符串 加密结果 不可逆 ,常用于用户的密码加密 注意:8.0起不再推荐使用,使用会报错 |
MD5(str) |
不可逆 返回字符串 str 的 MD5 加密后的值,也是一种加密方式 若参数为 NULL,则返回 NULL |
SHA(str) |
不可逆 从原明文密码 str 计算并返回加密后的密码字符串;当参数为 NULL 时,返回 NULL SHA 加密算法比 MD5 更加安全 |
ENCODE(value, password_seed) |
返回使用 password_seed 作为加密密钥对 value 进行加密 的结果 注意:8.0起不再推荐使用,使用会报错 |
DECODE(value, password_seed) |
返回使用 password_seed 作为解密密钥对 value 进行解密 的结果 注意:8.0起不再推荐使用,使用会报错 |
- ENCODE(value,password_seed)函数与DECODE(value,password_seed)函数互为反函数
7. MySQL信息函数
- MySQL中内置了一些可以查询MySQL信息的函数
- 作用: 帮助数据库开发或运维人员更好地对数据库进行维护工作
| 函数 |
用法 |
VERSION() |
返回当前 MySQL 的版本号 |
CONNECTION_ID() |
返回当前 MySQL 服务器的连接数 (即当前会话的连接 ID) |
DATABASE(), SCHEMA() |
返回 MySQL 命令行当前所在的数据库名 (二者等价,SCHEMA() 是 DATABASE() 的同义词) |
USER(), CURRENT_USER(), SYSTEM_USER(), SESSION_USER() |
返回当前 连接 MySQL 的用户名 ,返回结果格式为 "主机名@用户名" |
CHARSET(value) |
返回字符串 value 所使用的字符集 |
COLLATION(value) |
返回字符串 value 所使用的校对规则(排序规则) |
8. 其他函数
MySQL中有些函数无法 对其进行具体的分类
但是这些函数在MySQL的开发和运维过程中也是不容忽视的
| 函数 |
用法 |
FORMAT(value, n) |
返回对数字 value 进行格式化后的结果数据 n 表示 四舍五入 后保留到小数点后 n 位 注:如果n的值小于或者等于0,则只保留整数部分 |
CONV(value, from, to) |
将 value 的值在不同进制之间进行转换 (如十进制 ↔ 二进制 ↔ 十六进制等) from 和 to 为进制基数(2--36) |
INET_ATON(ipvalue) |
将以点分隔的 IP 地址 (如 '192.168.1.1')转化为一个无符号整数(32 位) |
INET_NTOA(value) |
将数字形式的 IP 地址(整数) 转化为以点分隔的 IP 地址字符串 (如 3232235777 → '192.168.1.1')。 |
BENCHMARK(n, expr) |
将表达式 expr 重复执行 n 次 ,用于测试 MySQL 处理该表达式所耗费的时间(常用于性能调优或基准测试)。 |
CONVERT(value USING char_code) |
将 value 所使用的字符编码修改为指定的 char_code (如 utf8mb4, latin1),实现字符集转换。 |
- 以"192.168.1.100"为例,计算方式为192乘以256的3次方,加上168乘以256的2次方,加上1乘以256,再加上100
sql
复制代码
mysql> SELECT BENCHMARK(1, MD5('mysql'));
+----------------------------+
| BENCHMARK(1, MD5('mysql')) |
+----------------------------+
| 0 |
+----------------------------+
1 row in set (0.00 sec)
mysql> SELECT BENCHMARK(1000000, MD5('mysql'));
+----------------------------------+
| BENCHMARK(1000000, MD5('mysql')) |
+----------------------------------+
| 0 |
+----------------------------------+
1 row in set (0.94 sec)