MySQL 8.0 常用内置函数用例
文章目录
- [MySQL 8.0 常用内置函数用例](#MySQL 8.0 常用内置函数用例)
-
- 读者问题、范围与核心结论
- 最小可复现实验集
- 函数条目如何阅读
- 字符串函数:清洗、拼接与编码
- 日期时间函数:时区、截断与区间
- 数学函数:数值计算与舍入规则
- 聚合函数:从明细到统计结果
- 窗口函数:保留明细的排名、累计与分组计算
- 条件函数:分支、空值与短路假设
- [JSON 函数:路径、抽取与修改](#JSON 函数:路径、抽取与修改)
- 类型转换函数:显式优于隐式
- 系统信息函数:诊断而非业务数据
- 相近函数对比:避免"能跑但语义错"
- 补充常用函数索引
-
- [逐函数最小 Demo 速查](#逐函数最小 Demo 速查)
- 失败路径、边界与排错清单
- 函数对索引与执行计划的影响
- 验证步骤与证据记录
- 取舍与维护建议
- 结论
- 附录:官方完整索引与扩展阅读
内容摘要:本文面向使用 MySQL 8.0 的开发者和数据分析人员,按字符串、日期时间、数学、聚合、窗口、条件、JSON、类型转换、系统信息九类整理最常用内置函数。每个条目给出功能、语法、参数、返回值、场景、边界、性能和常见错误,并提供可复制的初始化 SQL 与业务示例。函数行为以 MySQL 8.0 官方手册为依据;由于当前环境未连接可用 MySQL 服务端,示例结果标为"预期结果",需在目标实例复核。空间、全文、正则、加密等低频或专项函数通过官方索引扩展,不在本篇逐条展开。
读者问题、范围与核心结论
这份文档解决什么问题
函数参考最容易变成"名称 + 一行解释"的词典,但真正影响线上结果的是隐式类型转换、NULL 传播、字符集、时区、窗口排序和 JSON 路径。本文的主结论是:选择函数时,先确认输入类型、NULL 语义和是否会破坏索引,再讨论写法是否简短。
覆盖范围与非目标
- 覆盖 MySQL 8.0 中日常查询、报表、清洗和接口开发最常用的函数;这不是逐项收录全部内置函数的完整手册,同类低频函数在"官方索引"中给出入口。
- 包括聚合函数和窗口函数;窗口函数自 MySQL 8.0.2 起提供,本文按 MySQL 8.0 通用语义编写。
- 不把存储函数、用户自定义函数(UDF)、插件函数当作内置函数;空间、全文检索、复制/组复制专用函数仅列官方参考链接。
- 语法示例以 UTF-8、
sql_mode为常见默认配置为前提;严格模式、时区、排序规则会改变部分结果。
覆盖矩阵
| 分类 | 本文逐条覆盖 | 未逐条展开但可从官方索引扩展的内容 |
|---|---|---|
| 字符串 | 13 组 | 正则、编码转换、声音/空间专用字符串函数 |
| 日期时间 | 11 组 | 周、季度、时区转换及时间间隔构造函数 |
| 数学 | 10 组 | 对数、三角函数、位运算和随机分布函数 |
| 聚合 | 9 组 | 方差、标准差、位聚合和精确/近似统计函数 |
| 窗口 | 7 组 | 窗口聚合的全部变体和帧边界组合 |
| 条件 | 4 组 | 布尔谓词和表达式运算符 |
| JSON | 11 组 | JSON Schema、搜索、合并、格式化和高级索引函数 |
| 类型转换 | 4 组 | 二进制/字符集相关转换细节 |
| 系统信息 | 8 组 | UUID、加密摘要、性能模式和复制状态函数 |
证据边界
| 结论层次 | 本文能证明什么 | 仍需现场确认什么 |
|---|---|---|
| 官方语义 | 函数签名、参数规则、NULL 传播和版本章节来自 MySQL 8.0 Reference Manual |
具体小版本差异、弃用提示 |
| SQL 示例 | 示例可作为可执行模板;结果按确定性输入推导 | 目标实例的 sql_mode、字符集、时区和执行计划 |
| 性能建议 | 指出常见索引失效和排序/物化风险 | 真实数据量、统计信息、硬件和计划,必须用 EXPLAIN ANALYZE 验证 |
官方总目录:14 Functions and Operators。分类入口:字符串、日期时间、数学、聚合、窗口、流程控制、JSON、类型转换、信息函数。
最小可复现实验集
以下脚本只创建临时实验表,不依赖业务库。重复执行前可先删除表。DECIMAL 用于金额,避免用浮点数验证财务结果。
sql
SET NAMES utf8mb4;
DROP TABLE IF EXISTS demo_order;
CREATE TABLE demo_order (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
user_name VARCHAR(50) NOT NULL,
status VARCHAR(20) NOT NULL,
amount DECIMAL(12, 2) NOT NULL,
discount DECIMAL(5, 2) NULL,
tags JSON NULL,
created_at DATETIME NOT NULL,
updated_at TIMESTAMP NULL,
INDEX idx_order_user_created (user_id, created_at),
INDEX idx_order_status_created (status, created_at)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
INSERT INTO demo_order
(id, user_id, user_name, status, amount, discount, tags, created_at, updated_at)
VALUES
(1, 101, '张三', 'PAID', 129.90, 10.00, JSON_ARRAY('vip', 'book'), '2024-01-15 09:30:00', '2024-01-15 09:31:00'),
(2, 102, '李四', 'PENDING', 88.00, NULL, JSON_ARRAY('new'), '2024-02-20 10:00:00', '2024-02-20 10:00:00'),
(3, 101, '张三', 'PAID', 256.50, 20.00, JSON_ARRAY('vip', 'phone'), '2024-03-01 11:20:00', '2024-03-01 11:21:00'),
(4, 103, '王五', 'CANCELLED', 50.00, 0.00, NULL, '2024-03-05 16:00:00', NULL);
sql
-- 检查实例,结果受运行环境影响
SELECT VERSION() AS mysql_version, @@sql_mode AS sql_mode,
@@time_zone AS session_time_zone, @@character_set_connection AS connection_charset;
预期的确定性结果示例(未在本环境执行):
sql
SELECT CONCAT(user_name, ':', status) AS label,
ROUND(amount * (1 - COALESCE(discount, 0) / 100), 2) AS payable
FROM demo_order
WHERE id = 1;
| label | payable |
|---|---|
| 张三:PAID | 116.91 |
函数条目如何阅读
每个条目使用同一契约:功能/语法/参数/返回值/场景/边界/性能/错误。其中"版本"只有在官方手册明确有版本条件,或函数在 MySQL 8.0 中存在时才写;"未验证"表示本机没有可用服务端或该行为依赖现场配置。
字符串函数:清洗、拼接与编码
官方参考:String Functions and Operators。字符串位置从 1 开始;长度参数的非整数会按规则取整。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
CONCAT |
CONCAT(str1, str2, ...);参数为任意字符串表达式 |
返回拼接字符串;任一参数为 NULL 时返回 NULL。适合展示标签。避免把用户输入拼入 SQL。函数在 8.0 可用;结果字符集按参数聚合。 |
在 WHERE CONCAT(a,b)=... 上使用会阻断普通索引;可考虑生成列。常见错:误以为 NULL 会当空串。 |
CONCAT_WS |
CONCAT_WS(separator, str1, ...);第一个参数是分隔符 |
用分隔符拼接,后续 NULL 参数被跳过;分隔符为 NULL 时结果为 NULL。适合地址/CSV。空字符串不会被跳过。 |
大批量拼接会产生临时字符串;注意字符集。8.0 可用。 |
COALESCE |
COALESCE(expr1, expr2, ...) |
返回第一个非 NULL 值;全部为空返回 NULL。适合默认值和兼容字段。参数类型会参与类型推导。 |
WHERE COALESCE(index_col, 0)=? 可能无法走索引;优先改写为可索引谓词。8.0 可用。 |
IFNULL |
IFNULL(expr1, expr2) |
expr1 非空返回它,否则返回 expr2。仅二选一。类型转换可能与 COALESCE 不同。 |
不要用来掩盖数据缺失;金额默认值应显式 DECIMAL。8.0 可用。 |
LEFT / RIGHT |
LEFT(str,len)、RIGHT(str,len);len 为字符数 |
截取左右字符;NULL 输入返回 NULL,长度小于 0 返回空串。多字节字符按字符而非字节处理。 |
WHERE LEFT(code,3)=... 通常不能用前缀索引;可用 LIKE 'abc%' 或生成列。8.0 可用。 |
SUBSTRING |
SUBSTRING(str,pos[,len]);位置可为负数 |
按字符截取;负位置从末尾计算,超界返回空串,NULL 返回 NULL。 |
位置和长度误用字节会切坏中文;大字段截取有内存成本。8.0 可用。 |
LENGTH / CHAR_LENGTH |
LENGTH(str) 字节数;CHAR_LENGTH(str) 字符数 |
UTF-8 中文下二者通常不同;NULL 返回 NULL。 |
校验显示长度必须用 CHAR_LENGTH;协议字节数才用 LENGTH。8.0 可用。 |
LOWER / UPPER |
LOWER(str)、UPPER(str) |
按当前字符集的大小写映射转换;对非字母字符通常不变。 | 在谓词上包裹列会影响索引;需要大小写不敏感比较时优先选对排序规则。8.0 可用。 |
TRIM |
TRIM([remstr FROM] str),也支持 LEADING/TRAILING/BOTH |
去除两端空格或指定字符;不是正则替换。 | 清洗后写回可能改变唯一键;TRIM(col) 查询可能失去索引。8.0 可用。 |
REPLACE |
REPLACE(str,from_str,to_str) |
替换全部匹配;找不到时原样返回,任一参数 NULL 返回 NULL。 |
不能处理正则;大文本全量扫描。8.0 可用。 |
FIND_IN_SET |
FIND_IN_SET(str,strlist) |
返回逗号列表中位置,找不到 0,空参数或 NULL 有特殊结果。 |
不推荐把逗号列表当多值模型;无法有效使用普通索引。8.0 可用。 |
FORMAT |
FORMAT(X,D[,locale]) |
按 locale 格式化数字并返回字符串;适合展示,不适合继续计算。 | 结果含千分位,排序会变成字典序。8.0 可用;locale 行为需现场确认。 |
JSON_QUOTE |
JSON_QUOTE(string) |
将字符串转为合法 JSON 字符串字面量并转义。 | 不要把已是 JSON 的对象再次 quote;8.0 可用。 |
sql
SELECT user_name,
CONCAT_WS(' / ', NULLIF(TRIM(user_name), ''), status) AS display_name,
CHAR_LENGTH(user_name) AS char_count,
LENGTH(user_name) AS byte_count
FROM demo_order
WHERE id IN (1, 2);
预期:张三 的字符数为 2;在常见 utf8mb4 下字节数为 6。该字节数依连接字符集而变,需在目标实例核对。
日期时间函数:时区、截断与区间
官方参考:Date and Time Functions。DATETIME 不自动保存时区;TIMESTAMP 会结合会话/系统时区转换显示。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
NOW / CURRENT_TIMESTAMP |
NOW([fsp]) |
当前会话时间;同一条语句内通常保持一致。 | 不适合跨服务唯一时间戳;测试需注入时钟。8.0 可用。 |
CURDATE / CURRENT_DATE |
CURDATE() |
当前日期。 | 与服务器时区相关;不要用字符串比较日期。8.0 可用。 |
DATE / TIME |
DATE(expr)、TIME(expr) |
提取日期或时间部分;非法值可能返回 NULL/警告,严格模式行为不同。 |
WHERE DATE(created_at)=? 常使索引失效;改用半开区间。8.0 可用。 |
DATE_ADD / DATE_SUB |
DATE_ADD(date, INTERVAL expr unit) |
日期加减;月末、闰年会按日历规则调整。 | 单位必须是合法关键字;跨 DST 时不要把天等同 24 小时。8.0 可用。 |
DATEDIFF |
DATEDIFF(expr1,expr2) |
返回日期部分相差天数,忽略时间。 | 需要精确时长应使用 TIMESTAMPDIFF;8.0 可用。 |
TIMESTAMPDIFF |
TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) |
按单位返回整数差值,截断小数单位。 | 单位选择会影响结果(MONTH 不是固定 30 天);8.0 可用。 |
DATE_FORMAT |
DATE_FORMAT(date,format) |
按格式返回字符串,如 %Y-%m-%d。 |
只用于展示/分组标签;不要对结果再做日期比较。8.0 可用。 |
STR_TO_DATE |
STR_TO_DATE(str,format) |
按格式解析字符串为日期时间;不匹配返回 NULL 或警告。 |
输入校验应在边界层完成;格式符错误是常见原因。8.0 可用。 |
EXTRACT |
EXTRACT(unit FROM date) |
提取年、月、日、小时等数值部分。 | 同样可能破坏索引;8.0 可用。 |
LAST_DAY |
LAST_DAY(date) |
返回月份最后一天;无效日期返回 NULL。 |
可用于账期边界;注意 DATETIME 结果被截为日期。8.0 可用。 |
UNIX_TIMESTAMP / FROM_UNIXTIME |
UNIX_TIMESTAMP([date])、FROM_UNIXTIME(unix_timestamp[,format]) |
在日期与 Unix 秒之间转换;受时区影响。 | 2038、时区、毫秒单位是常见坑;毫秒输入需先除以 1000。8.0 可用。 |
推荐的可索引时间范围写法:
sql
SELECT id, created_at
FROM demo_order
WHERE created_at >= '2024-03-01 00:00:00'
AND created_at < '2024-04-01 00:00:00';
不要写成 WHERE DATE(created_at) = '2024-03-01',除非已用生成列/函数索引并验证执行计划。
数学函数:数值计算与舍入规则
官方参考:Mathematical Functions。除非另有说明,NULL 输入通常返回 NULL;溢出、非法转换和除零受 sql_mode 影响。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
ABS |
ABS(X) |
绝对值;最小有符号整数取绝对值可能溢出。 | 金额先确认 DECIMAL;8.0 可用。 |
ROUND |
ROUND(X[,D]) |
按位数四舍五入;D 可为负数。精确值与近似值舍入细节不同。 |
仅展示时不要提前舍入;金额规则应由业务确认。8.0 可用。 |
TRUNCATE |
TRUNCATE(X,D) |
截断而非四舍五入;D 为负数可截断整数位。 |
不要把它当财务舍入;8.0 可用。 |
CEIL / CEILING |
CEIL(X) |
向上取整。 | 负数结果与直觉不同;8.0 可用。 |
FLOOR |
FLOOR(X) |
向下取整。 | 负数向更小方向取整;8.0 可用。 |
MOD |
MOD(N,M) 或 N % M |
取模;除数为 0 时返回 NULL。 |
分页/分桶前校验除数;8.0 可用。 |
POWER / POW |
POWER(X,Y) |
幂运算,可能返回近似数或溢出。 | 科学计算需控制精度;8.0 可用。 |
SQRT |
SQRT(X) |
非负平方根;负数返回 NULL。 |
先校验域;8.0 可用。 |
RAND |
RAND([seed]) |
伪随机数;无 seed 时每次调用可能不同。 | ORDER BY RAND() 会全表计算和排序,不适合大表抽样。8.0 可用。 |
SIGN |
SIGN(X) |
负数 -1、0 为 0、正数 1。 | 比 IF 更适合分类;8.0 可用。 |
sql
SELECT amount,
ROUND(amount * (1 - COALESCE(discount, 0) / 100), 2) AS payable,
CEIL(amount) AS upper_amount,
MOD(id, 2) AS bucket
FROM demo_order;
聚合函数:从明细到统计结果
官方参考:Aggregate Function Descriptions。聚合会忽略大多数 NULL 值;空集合下 COUNT 返回 0,SUM/AVG 等通常返回 NULL。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
COUNT(*) |
COUNT(*) |
行数,不因列为 NULL 而减少。 |
统计存在性优先用 COUNT(*);8.0 可用。 |
COUNT(expr) |
COUNT(expr) |
统计表达式非 NULL 的行。 |
与 COUNT(*) 混淆会少算;8.0 可用。 |
COUNT(DISTINCT expr) |
去重后计数;多列写法需确认版本/语义 | 返回非空唯一值数量;大基数可能使用临时表。 | 先评估内存和索引;8.0 可用。 |
SUM |
SUM([DISTINCT] expr) |
求和;无行或全空通常为 NULL。 |
金额用 DECIMAL;溢出需关注类型范围。8.0 可用。 |
AVG |
AVG([DISTINCT] expr) |
平均值;等价于 SUM/COUNT 的语义组合。 |
分母为 0 时结果 NULL;8.0 可用。 |
MIN / MAX |
MIN(expr)、MAX(expr) |
最小/最大非空值;字符串按排序规则比较。 | 字符串排序规则会影响结果;8.0 可用。 |
GROUP_CONCAT |
GROUP_CONCAT([DISTINCT] expr ORDER BY ... SEPARATOR str) |
将组内值拼成字符串;受 group_concat_max_len 限制,可能截断。 |
不用于传输结构化数据;需要 JSON 时用 JSON_ARRAYAGG。8.0 可用。 |
JSON_ARRAYAGG |
JSON_ARRAYAGG(col_or_expr) |
聚合为 JSON 数组;顺序未指定,不能依赖自然顺序。 | 结果可能很大;8.0.14 起支持窗口形式。 |
JSON_OBJECTAGG |
JSON_OBJECTAGG(key,value) |
聚合为 JSON 对象;键为 NULL 会报错,重复键通常由后值覆盖前值,但输入顺序未定义时不能依赖最终覆盖结果。 |
先确保键唯一;8.0.14 起支持窗口形式。 |
sql
SELECT status,
COUNT(*) AS order_count,
COALESCE(SUM(amount), 0.00) AS gross_amount,
AVG(amount) AS average_amount,
GROUP_CONCAT(id ORDER BY id SEPARATOR ',') AS order_ids
FROM demo_order
GROUP BY status;
预期分组行数:PAID=2、PENDING=1、CANCELLED=1;金额结果按 DECIMAL 计算,具体格式以客户端显示为准。
窗口函数:保留明细的排名、累计与分组计算
官方参考:Window Function Descriptions。窗口函数在不折叠明细行的前提下计算分组统计;ORDER BY 决定顺序,未指定稳定排序时并列行顺序不可依赖。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
ROW_NUMBER |
ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) |
每个分区从 1 开始的唯一序号;并列也会被打散。 | 分页需使用稳定唯一键作为次排序;MySQL 8.0.2+。 |
RANK |
RANK() OVER (...) |
并列同名次,后续名次跳跃。 | 竞赛排名适用;MySQL 8.0.2+。 |
DENSE_RANK |
DENSE_RANK() OVER (...) |
并列同名次,后续名次不跳跃。 | 分层统计适用;MySQL 8.0.2+。 |
LAG / LEAD |
LAG(expr[,N[,default]]) OVER (...) |
访问前/后 N 行;越界返回默认值或 NULL。 |
必须指定合理排序;MySQL 8.0.2+。 |
FIRST_VALUE / LAST_VALUE |
FIRST_VALUE(expr) OVER (...) |
取窗口帧首/尾值;默认帧可能使 LAST_VALUE 只看到当前行。 |
使用 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 明确全分区;MySQL 8.0.2+。 |
NTILE |
NTILE(N) OVER (...) |
将分区尽量平均分为 N 桶。 | N 必须为正整数;MySQL 8.0.2+。 |
CUME_DIST / PERCENT_RANK |
CUME_DIST() OVER (...)、PERCENT_RANK() OVER (...) |
计算累计分布/百分比排名。 | 小样本边界值容易误读;MySQL 8.0.2+。 |
sql
SELECT id, user_id, amount,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at, id) AS seq,
SUM(amount) OVER (
PARTITION BY user_id
ORDER BY created_at, id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_amount,
LAG(amount) OVER (PARTITION BY user_id ORDER BY created_at, id) AS previous_amount
FROM demo_order;
常见错误是把窗口函数直接写进 WHERE;应先放在派生表/CTE,再在外层过滤:
sql
WITH ranked AS (
SELECT d.*, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at, id) AS rn
FROM demo_order AS d
)
SELECT * FROM ranked WHERE rn = 1;
条件函数:分支、空值与短路假设
官方参考:Flow Control Functions。不要把"看起来只会执行一个分支"当作可移植的副作用控制机制;表达式类型推导和优化器行为需实测。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
IF |
IF(condition, true_expr, false_expr) |
条件真/假返回不同表达式;NULL 条件按非真处理。 |
复杂逻辑可读性差,优先 CASE;8.0 可用。 |
CASE |
CASE WHEN cond THEN expr [WHEN ...] [ELSE expr] END 或简单 CASE |
返回首个满足条件的分支;无匹配且无 ELSE 返回 NULL。 |
分支类型需兼容;不要遗漏 ELSE。8.0 可用。 |
NULLIF |
NULLIF(expr1,expr2) |
相等返回 NULL,否则返回 expr1。 |
常用于防止除零:a / NULLIF(b,0);8.0 可用。 |
IFNULL |
见字符串章节 | 二选一默认值;类型推导需确认。 | 与 COALESCE 的多参数能力不同;8.0 可用。 |
sql
SELECT id, status,
CASE status
WHEN 'PAID' THEN '已支付'
WHEN 'PENDING' THEN '待支付'
WHEN 'CANCELLED' THEN '已取消'
ELSE '未知'
END AS status_label,
amount / NULLIF(discount, 0) AS amount_per_discount
FROM demo_order;
JSON 函数:路径、抽取与修改
官方参考:JSON Function Reference。JSON 路径使用 $ 根、. 成员和 [N] 数组下标;不存在路径通常得到 NULL 或 0/1,需按函数语义判断。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
JSON_EXTRACT / -> |
JSON_EXTRACT(json_doc,path[,path...]);col->'$.a' 是简写 |
返回 JSON 值;多路径返回数组;不存在路径返回 NULL。 |
结果仍是 JSON,字符串可能带引号;8.0 可用。 |
->> |
col->>'$.a' |
等价于 JSON_UNQUOTE(JSON_EXTRACT(...)),返回未加引号文本。 |
与 -> 混用会导致比较失败;8.0 可用。 |
JSON_UNQUOTE |
JSON_UNQUOTE(json_val) |
去掉 JSON 字符串引号并处理转义;非字符串 JSON 原样返回。 | 不要对普通 SQL 字符串误用;8.0 可用。 |
JSON_CONTAINS |
JSON_CONTAINS(target,candidate[,path]) |
包含返回 1,否则 0;对象比较是键值语义。 | 路径错误或文档非法会报错;8.0 可用。 |
JSON_CONTAINS_PATH |
JSON_CONTAINS_PATH(json_doc,one_or_all,path...) |
判断路径是否存在,返回 1/0。 | one 与 all 语义不同;8.0 可用。 |
JSON_SET |
JSON_SET(json_doc,path,val[,path,val]...) |
存在则更新,不存在则添加。 | 更新大 JSON 会重写文档;8.0 可用。 |
JSON_INSERT |
JSON_INSERT(json_doc,path,val,...) |
只插入不存在路径,已有值不覆盖。 | 与 JSON_SET 混淆会产生静默不更新;8.0 可用。 |
JSON_REPLACE |
JSON_REPLACE(json_doc,path,val,...) |
只替换已存在路径,不新增。 | 需要判断是否成功时同时用 JSON_CONTAINS_PATH;8.0 可用。 |
JSON_REMOVE |
JSON_REMOVE(json_doc,path,...) |
删除指定路径。 | 路径不存在通常不报错;8.0 可用。 |
JSON_ARRAY / JSON_OBJECT |
JSON_ARRAY(val,...)、JSON_OBJECT(key,val,...) |
构造 JSON 数组/对象;对象键不能为 NULL。 |
值类型由 SQL 类型决定;8.0 可用。 |
JSON_TABLE |
JSON_TABLE(expr,path COLUMNS(...)) |
将 JSON 展开为关系表;需定义列路径、类型和错误处理。 | 可能产生大量行;先限制文档规模。8.0.4+。 |
sql
SELECT id,
user_name,
tags->>'$[0]' AS first_tag,
JSON_CONTAINS(tags, JSON_QUOTE('vip')) AS is_vip,
JSON_SET(COALESCE(tags, JSON_ARRAY()), '$[2]', 'featured') AS enriched_tags
FROM demo_order;
可索引场景优先建立生成列或多值索引(多值索引依赖 InnoDB 与目标 8.0 小版本,且只能用于数组等特定 JSON 结构),不要在高选择性查询中反复对整列 JSON 解析。
类型转换函数:显式优于隐式
官方参考:Cast Functions and Operators。隐式转换可能产生警告、截断或索引失效;接口边界和比较条件尽量显式转换。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
CAST |
CAST(expr AS type);常见类型 CHAR、DATE、DATETIME、DECIMAL、SIGNED、UNSIGNED、JSON |
转为目标类型;非法值在严格模式下可能报错,否则可能产生警告/截断。 | 对索引列 CAST 常使索引失效;优先转换参数。8.0 可用。 |
CONVERT |
CONVERT(expr, type) 或 CONVERT(expr USING charset) |
类型或字符集转换;与 CAST 功能重叠。 |
字符集转换可能丢失字符;8.0 可用。 |
BINARY |
BINARY expr |
将表达式按二进制字符串比较,影响大小写和排序。 | 可能改变索引使用与排序结果;优先设置正确排序规则。8.0 可用。 |
HEX / UNHEX |
HEX(str)、UNHEX(hex_str) |
二进制与十六进制字符串互转;奇数/非法十六进制有边界行为。 | 仅用于编码展示或传输,不能当加密;8.0 可用。 |
sql
SELECT CAST('2024-03-01' AS DATE) AS d,
CAST('12.50' AS DECIMAL(10,2)) AS n,
CONVERT('abc' USING utf8mb4) AS text_value;
系统信息函数:诊断而非业务数据
官方参考:Information Functions。这些函数反映当前连接、会话或实例状态;不要把连接 ID、版本号等动态信息持久化为业务事实。
| 函数 | 功能、语法与参数 | 返回值、场景与边界 | 性能、常见错误、版本 |
|---|---|---|---|
VERSION |
VERSION() |
返回服务器版本字符串,可能带发行信息。 | 用于诊断/能力探测,不要硬编码字符串比较;8.0 可用。 |
DATABASE / SCHEMA |
DATABASE()、SCHEMA() |
当前默认数据库;未选择数据库返回 NULL。 |
连接池复用时不要假设默认库;8.0 可用。 |
USER / CURRENT_USER |
USER() 返回客户端认证用户;CURRENT_USER() 返回授权账户 |
二者可能不同,后者用于权限判断。 | 审计应记录服务端认证结果;8.0 可用。 |
CONNECTION_ID |
CONNECTION_ID() |
当前连接 ID。 | 只适合诊断和杀会话;不能作业务主键。8.0 可用。 |
LAST_INSERT_ID |
LAST_INSERT_ID([expr]) |
无参取最近自增值;带参会设置会话值。 | 并发连接隔离;不要跨连接读取。8.0 可用。 |
ROW_COUNT |
ROW_COUNT() |
返回上一条语句影响行数;对 SELECT 等语句语义不同。 | 必须紧接目标语句调用;8.0 可用。 |
FOUND_ROWS |
FOUND_ROWS() |
与 SQL_CALC_FOUND_ROWS 相关;SQL_CALC_FOUND_ROWS 和 FOUND_ROWS() 自 MySQL 8.0.17 起弃用。 |
分页应使用独立 COUNT(*) 或窗口策略;预计未来版本移除,不建议新代码使用。 |
ISNULL |
ISNULL(expr) |
为空返回 1,否则 0。 | 与 expr IS NULL 等价表达式相比可读性按团队规范选择;8.0 可用。 |
相近函数对比:避免"能跑但语义错"
补充常用函数索引
下表补上正文主表未逐项展开、但在日常开发中仍较常见的函数。它们遵循同样的核对原则:先看官方语义,再用目标实例验证边界和执行计划。
| 分类 | 函数 | 用途与关键边界 | 官方入口 |
|---|---|---|---|
| 字符串 | ASCII、LOCATE、INSTR、LPAD、RPAD、REVERSE、REPEAT、STRCMP |
字符编码、查找、填充、反转、重复和字典序比较;长度、空串、字符集会影响结果 | 字符串函数 |
| 日期时间 | YEAR、MONTH、DAY、QUARTER、WEEK、WEEKDAY、DAYOFWEEK、CONVERT_TZ |
提取日历字段、周计算和时区转换;周模式、时区表加载和夏令时必须现场确认 | 日期时间函数 |
| 数学 | LOG、LOG10、EXP、PI、SIN、COS、TAN |
对数、指数和三角计算;输入定义域、近似值和溢出是主要边界 | 数学函数 |
| 聚合 | STDDEV_POP、STDDEV_SAMP、VAR_POP、VAR_SAMP、BIT_AND、BIT_OR、BIT_XOR |
离散统计与位聚合;空集合、样本量和无符号位宽需单独测试 | 聚合函数 |
| 条件 | GREATEST、LEAST |
返回多个表达式的最大/最小值;任一参数为 NULL 时通常传播 NULL,混合类型需注意转换 |
流程控制函数 |
| JSON | JSON_DEPTH、JSON_KEYS、JSON_LENGTH、JSON_PRETTY、JSON_SEARCH、JSON_VALUE、JSON_OVERLAPS |
JSON 结构分析、搜索、标量提取与重叠判断;路径、返回类型、错误处理和版本差异需核对 | JSON 函数 |
| 标识/摘要 | UUID、UUID_TO_BIN、BIN_TO_UUID、MD5、SHA2 |
UUID 生成/转换和摘要计算;摘要不是密码存储方案,UUID 排序与字节序参数需保持一致 | 信息函数、加密函数 |
以上函数未在本文逐个给出完整结果表,原因是部分行为依赖字符集、周模式、时区表、输入定义域或实例配置;扩展时应复制本文的函数条目模板,而不是只添加名称。
| 对比 | 关键差异 | 选择建议 |
|---|---|---|
IFNULL vs COALESCE |
前者固定两个参数;后者按从左到右取首个非空值,且遵循标准 SQL | 只有二选一用 IFNULL;需要多个候选或跨数据库兼容用 COALESCE。 |
IF vs CASE |
IF 是 MySQL 专用三参数函数;CASE 可多分支并更易表达业务规则 |
简单二分可用 IF;多状态、需迁移或需审计时用 CASE。 |
ROUND vs TRUNCATE |
ROUND 四舍五入;TRUNCATE 直接截断 |
财务规则先确认舍入方式;展示层不要改变存储值。 |
LENGTH vs CHAR_LENGTH |
字节数 vs 字符数 | 协议/存储容量用 LENGTH;用户可见长度用 CHAR_LENGTH。 |
DATEDIFF vs TIMESTAMPDIFF |
前者只算日期天数;后者可指定单位并考虑时间部分 | 账期天数用 DATEDIFF;年龄、分钟、月份差用 TIMESTAMPDIFF。 |
COUNT(*) vs COUNT(col) |
前者统计行;后者忽略列为 NULL 的行 |
统计行数用 COUNT(*);统计非空值才用 COUNT(col)。 |
GROUP_CONCAT vs JSON_ARRAYAGG |
前者文本拼接且长度受配置限制;后者结构化 JSON | 给人看或兼容旧接口用前者;下游程序消费用后者。 |
-> vs ->> |
前者返回 JSON 值;后者返回去引号文本 | 继续 JSON 运算用 ->;与 SQL 文本比较/展示用 ->>。 |
JSON_SET vs JSON_INSERT vs JSON_REPLACE |
更新并可新增;只新增;只更新 | 根据"字段不存在时是否创建"明确选择,避免静默数据错误。 |
逐函数最小 Demo 速查
下面的语句为前述条目的最小可执行调用;它们用于确认返回类型和边界,不替代业务数据测试。结果中带当前时间、随机数、实例信息或排序的语句,不给出固定快照。
sql
-- 字符串
SELECT ASCII('A'), CHAR_LENGTH('中文'), LENGTH('中文'),
LOWER('AbC'), UPPER('AbC'), LEFT('abcdef', 2), RIGHT('abcdef', 2),
SUBSTRING('abcdef', 2, 3), TRIM(' x '), REPLACE('a-b', '-', '_'),
CONCAT('a', 'b'), CONCAT_WS('-', 'a', NULL, 'b'),
COALESCE(NULL, NULL, 'fallback'), IFNULL(NULL, 'fallback'),
FIND_IN_SET('b', 'a,b,c'), FORMAT(12345.6, 2), JSON_QUOTE('a"b');
-- 日期时间
SELECT NOW(), CURRENT_TIMESTAMP, CURDATE(), CURRENT_DATE,
DATE('2024-03-01 12:30:00'), TIME('2024-03-01 12:30:00'),
DATE_ADD('2024-01-31', INTERVAL 1 MONTH),
DATE_SUB('2024-03-01', INTERVAL 1 DAY),
DATEDIFF('2024-03-05', '2024-03-01'),
TIMESTAMPDIFF(HOUR, '2024-03-01 00:00:00', '2024-03-01 03:30:00'),
DATE_FORMAT('2024-03-01', '%Y-%m'),
STR_TO_DATE('2024/03/01', '%Y/%m/%d'),
EXTRACT(YEAR FROM '2024-03-01'), LAST_DAY('2024-02-01'),
FROM_UNIXTIME(1709251200), UNIX_TIMESTAMP('2024-03-01 00:00:00');
-- 数学
SELECT ABS(-3), ROUND(12.345, 2), TRUNCATE(12.345, 2),
CEIL(2.1), CEILING(2.1), FLOOR(2.9), MOD(10, 3),
POWER(2, 3), SQRT(9), SIGN(-8), RAND(7);
-- 聚合
SELECT COUNT(*), COUNT(discount), COUNT(DISTINCT user_id),
SUM(amount), AVG(amount), MIN(amount), MAX(amount),
GROUP_CONCAT(id ORDER BY id), JSON_ARRAYAGG(id),
JSON_OBJECTAGG(id, status)
FROM demo_order;
-- 条件与类型转换
SELECT IF(amount > 100, '大额', '普通'),
CASE status WHEN 'PAID' THEN '已支付' ELSE '其他' END,
NULLIF(discount, 0),
CAST('12.50' AS DECIMAL(10,2)), CONVERT('12' , SIGNED),
CONVERT('中文' USING utf8mb4), BINARY 'Ab' = BINARY 'ab',
HEX('A'), UNHEX('41')
FROM demo_order WHERE id = 1;
-- JSON 与系统信息
SELECT tags->'$[0]', tags->>'$[0]', JSON_EXTRACT(tags, '$[0]'),
JSON_UNQUOTE(JSON_QUOTE('x')), JSON_CONTAINS(tags, JSON_QUOTE('vip')),
JSON_CONTAINS_PATH(tags, 'one', '$[0]'),
JSON_SET(COALESCE(tags, JSON_ARRAY()), '$[1]', 'x'),
JSON_INSERT(COALESCE(tags, JSON_ARRAY()), '$[1]', 'x'),
JSON_REPLACE(COALESCE(tags, JSON_ARRAY()), '$[0]', 'x'),
JSON_REMOVE(COALESCE(tags, JSON_ARRAY()), '$[0]'),
JSON_ARRAY('a', 1), JSON_OBJECT('k', 1),
VERSION(), DATABASE(), SCHEMA(), USER(), CURRENT_USER(), CONNECTION_ID(),
LAST_INSERT_ID(), ROW_COUNT(), ISNULL(discount)
FROM demo_order WHERE id = 1;
sql
-- 窗口函数:同一条语句保留明细行
SELECT id, user_id, amount,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at, id) AS rn,
RANK() OVER (PARTITION BY user_id ORDER BY amount DESC, id) AS rnk,
DENSE_RANK() OVER (PARTITION BY user_id ORDER BY amount DESC, id) AS dense_rnk,
LAG(amount, 1, 0) OVER (PARTITION BY user_id ORDER BY created_at, id) AS prev_amount,
LEAD(amount, 1, 0) OVER (PARTITION BY user_id ORDER BY created_at, id) AS next_amount,
FIRST_VALUE(amount) OVER (
PARTITION BY user_id ORDER BY created_at, id
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS first_amount,
LAST_VALUE(amount) OVER (
PARTITION BY user_id ORDER BY created_at, id
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_amount,
NTILE(2) OVER (ORDER BY amount DESC, id) AS bucket,
CUME_DIST() OVER (ORDER BY amount) AS cume_dist_value,
PERCENT_RANK() OVER (ORDER BY amount) AS percent_rank_value
FROM demo_order;
JSON_TABLE 需要表值展开,示例单独写出以突出列契约:
sql
SELECT jt.tag
FROM demo_order AS d,
JSON_TABLE(d.tags, '$[*]' COLUMNS(tag VARCHAR(20) PATH '$')) AS jt
WHERE d.id = 1;
预期 JSON_TABLE 返回 vip、book 两行;若 tags 为 SQL NULL 或 JSON null,不要与"路径不存在"混淆。JSON null 行为在 MySQL 8.0.21 有调整,必须在目标小版本验证。
失败路径、边界与排错清单
NULL 传播
sql
SELECT CONCAT('金额=', NULL) AS concat_result,
COALESCE(NULL, 0) AS coalesce_result,
COUNT(discount) AS non_null_discount_count,
COUNT(*) AS row_count
FROM demo_order;
预期:CONCAT 结果为 NULL,COALESCE 为 0,COUNT(discount) 小于 COUNT(*)。若结果不同,先检查表达式和数据,而不是先改函数。
日期谓词不走索引
sql
EXPLAIN ANALYZE
SELECT * FROM demo_order WHERE DATE(created_at) = '2024-03-01';
EXPLAIN ANALYZE
SELECT * FROM demo_order
WHERE created_at >= '2024-03-01 00:00:00'
AND created_at < '2024-03-02 00:00:00';
第二种写法通常更利于使用 created_at 索引,但"通常"不是保证;必须在目标数据量和统计信息上验证。
类型和字符集错误
ERROR 1292或截断警告:检查字符串日期、数字转换和sql_mode。- 中文长度不符合预期:同时查看
CHAR_LENGTH、LENGTH、连接字符集和列字符集。 - 金额出现
0.1 + 0.2类似精度问题:检查是否使用了DOUBLE/FLOAT,财务列改用DECIMAL。
窗口函数结果不稳定
排名、分页和 LAG 必须提供能唯一确定顺序的键,例如 ORDER BY created_at, id。只有时间字段时,同一时间的行顺序未定义。
JSON 路径为空
先用 JSON_VALID、JSON_TYPE、JSON_CONTAINS_PATH 区分"文档非法""路径不存在""值为 JSON null"三种情况,不要仅凭客户端显示的 NULL 判断。
函数对索引与执行计划的影响
函数放在索引列上,常会让优化器无法直接使用普通 B-Tree 索引。下面是"风险模式 → 常见改写"的对照;"通常"不等于保证,最终结论必须以目标实例的 EXPLAIN 或 EXPLAIN ANALYZE 为准。
| 风险写法 | 常见改写 | 仍需验证 |
|---|---|---|
WHERE DATE(created_at) = '2024-03-01' |
created_at >= '2024-03-01' AND created_at < '2024-03-02' |
时区、边界、索引选择 |
WHERE LOWER(user_name) = 'zhangsan' |
使用合适排序规则,或建立生成列/函数索引 | 排序规则与唯一性 |
WHERE CAST(order_no AS CHAR) = '1001' |
让参数转换为列的真实类型 | 隐式转换警告 |
WHERE JSON_EXTRACT(tags, '$[0]') = 'vip' |
生成列、JSON 索引或多值索引 | 8.0 小版本与数据分布 |
WHERE CONCAT(code, region) = 'A-1' |
拆成可索引列条件,或建立生成列 | 组合键语义 |
EXPLAIN ANALYZE 需要 MySQL 8.0.18 及以上;更早的 8.0 版本使用 EXPLAIN,不能把命令直接复制到所有 8.0 实例。完整实验脚本见 mysql-8函数参考-实验脚本.sql。
验证步骤与证据记录
在隔离 MySQL 8.0 实例上执行。以下是 mysql 客户端命令和 SQL 的混合示意 ,SOURCE 不是服务端 SQL,<代表性查询> 必须替换为真实语句:
sql
SELECT VERSION(), @@sql_mode, @@time_zone,
@@character_set_connection, @@collation_connection;
SHOW WARNINGS;
mysql 客户端命令:
text
SOURCE /path/to/mysql-8函数参考-实验脚本.sql
MySQL 8.0.18+ 的 SQL 示例:
sql
EXPLAIN ANALYZE
SELECT * FROM demo_order
WHERE created_at >= '2024-03-01 00:00:00'
AND created_at < '2024-03-02 00:00:00';
验证记录应至少包含:
- 实例版本、小版本、存储引擎、字符集、排序规则和时区;
- 每类至少一个
NULL、空集合、非法输入和边界值用例; - 关键查询的
EXPLAIN/EXPLAIN ANALYZE,不能用函数名称推断索引一定生效; - 结果集截图或导出文件,确保客户端没有自动格式化或时区转换;
- 对失败 SQL 记录错误码、警告和
sql_mode。
当前已证明:本文的函数签名、分类和注意事项有 MySQL 8.0 官方手册链接支撑;示例 SQL 语法按 MySQL 8.0 书写。当前未证明:本机真实服务端执行、生产数据性能、特定 8.0 小版本的全部兼容性,以及业务时区/权限配置下的最终结果。
取舍与维护建议
- "所有常用函数"比"所有函数"更适合团队手册;若要做完整参考,应以官方目录为索引,按低频类别拆分文档。
- 示例追求可复制,但不把一条示例外推为生产性能结论;涉及索引、窗口排序、JSON 大文档时必须补执行计划和数据规模。
- 将展示格式(
DATE_FORMAT、FORMAT)与业务值计算分开,避免把字符串写回数值/日期列。 - 将
NULL语义写进接口契约:默认值是0、空串还是保持NULL,必须由业务决定。 - MySQL 升级时重跑本页"验证步骤",特别是弃用函数、JSON_TABLE、窗口函数和 SQL 模式相关行为。
结论
这份参考文档覆盖 MySQL 8.0 日常开发最常用的九类内置函数,并把语法之外的 NULL、类型、时区、字符集、窗口顺序、JSON 路径和索引边界纳入同一套检查。可以直接用最小实验集开始验证;在连接真实实例前,不应把示例预期结果或性能建议当成生产验收结论。