本文总结了Oracle转MySQL时需注意的核心函数差异,重点解析了日期处理、NULL值处理、条件判断等高频考点函数的使用方法。
关键点包括:
MySQL日期函数如NOW()、DATEDIFF()的用法及与Oracle的对比;
NULL处理的IFNULL()和COALESCE()函数区别;
字符串拼接必须使用CONCAT而非||;
DATEDIFF()会自动忽略时分秒,TIMESTAMPDIFF()可计算精确时间差。
文章通过典型场景示例和易错点分析,帮助开发者快速适应MySQL语法特点,提高SQL编写效率和正确性。
从 Oracle 转战 MySQL,最关键的差异就是函数名和 NULL 的处理方式。xxx的 SQL 在线评测通常使用 MySQL,掌握下表的核心函数可以帮你快速通过测试。
以下是做题时最常用到的 MySQL 函数总结:
📊 MySQL 核心函数速查表
(注:加粗函数为xxx高频考点)
1. 日期时间处理(必考)
| 功能分类 | MySQL 函数 | 示例/说明 | Oracle 对比 | 高频场景 |
|---|---|---|---|---|
| 获取当前时间 | NOW() |
返回日期和时间 2025-05-12 10:00:00 |
SYSDATE |
记录操作时间 |
CURDATE() |
返回当前日期 2025-05-12 |
TRUNC(SYSDATE) |
按日期分组统计 | |
| 日期差值 | DATEDIFF(date1, date2) |
date1 - date2 的天数 (整数) |
date1 - date2 (直接减) |
计算用户留存、逾期天数 |
| 日期加减 | DATE_ADD(date, INTERVAL n UNIT) |
DATE_ADD('2025-05-01', INTERVAL 1 DAY) |
date + n |
有效期推算,牛客题常用 |
| 格式化 | DATE_FORMAT(date, format) |
DATE_FORMAT('2025-05-12, '%Y-%m')→2025-05`[citation:1] |
TO_CHAR\ | 按月/年统计 | |
|
| 提取部分 | YEAR(date), MONTH(date) |
直接提取年份或月份数字 | EXTRACT(YEAR FROM date) |
筛选特定月份数据 |
2. NULL 值处理(易错点)
| 功能分类 | MySQL 函数 | 示例/说明 | Oracle 对比 | 高频场景 |
|---|---|---|---|---|
| 空值转默认值 | IFNULL(expr, default) |
若expr为NULL,返回default |
NVL |
最常用,处理查询中的空值 |
| 条件判空 | IS NULL / IS NOT NULL |
WHERE phone IS NULL |
同MySQL | 排查缺失数据 |
| 空值合并 | COALESCE(val1, val2, ...) |
返回第一个非空值 | 同MySQL | 多字段优先级取值 |
| 判断后运算 | NULLIF(expr1, expr2) |
相等返回NULL,否则返回expr1 |
同MySQL | 避免除零错误 |
IFNULL(expr, default)和COALESCE(val1, val2, ...)的核心区别:参数数量 和返回值类型推断。
对比维度 IFNULL(expr, default)COALESCE(val1, val2, ...)参数个数 固定 2个 至少1个,可多个 返回逻辑 第1个非NULL → 返回 expr否则 → 返回default从左到右,返回第一个非NULL值 标准兼容性 MySQL特有函数 SQL标准函数 (Oracle/PostgreSQL/SQL Server都支持) 典型场景 简单二选一: IFNULL(score, 0)多字段优先级: COALESCE(手机, 微信, 邮箱, '无联系方式')一句话总结
只有两个值处理空值 → 用
IFNULL(MySQL专属,更简洁)多个值取第一个非空 → 用
COALESCE(跨数据库通用,更强大)
3. 条件判断(逻辑核心)
| 功能分类 | MySQL 函数 | 示例/说明 | Oracle 对比 | 高频场景 |
|---|---|---|---|---|
| 简单条件 | IF(condition, true_val, false_val) |
IF(score>=60, '及格', '不及格') |
DECODE 或 CASE |
分值转换、等级划分 |
| 多路分支 | CASE WHEN ... THEN ... END |
通用性强,支持任意逻辑 | 同MySQL | 复杂业务逻辑映射 |
| 行转列 | IF() 或 SUM(CASE...) |
常配合聚合函数进行条件计数 | PIVOT |
交叉表统计 -> xxx必考 |
4. 字符串处理(数据清洗)
| 功能分类 | MySQL 函数 | 示例/说明 | Oracle 对比 | 高频场景 |
|---|---|---|---|---|
| 拼接 | CONCAT(str1, str2, ...) 或 CONCAT_WS(separator, ...) |
CONCAT(first_name, last_name) |
` | |
| 截取 | SUBSTRING(str, pos, len) |
SUBSTRING('abcde', 2, 3) → bcd |
SUBSTR |
提取身份证、手机号片段 |
| 长度 | CHAR_LENGTH(str) (字符数) / LENGTH(str) (字节数) |
中文字符下长度不同 | LENGTH |
限制显示字数 |
| 大小写 | UPPER(str) |
转大写 | 同MySQL | 统一格式比较 |
| 去除空格 | TRIM([BOTH/LEADING/TRAILING] ... FROM str) |
默认删除首尾空格 | 同MySQL | 清洗用户输入数据 |
| 替换 | REPLACE(str, from_str, to_str) |
替换字符串中的内容 | REPLACE |
脱敏、格式化文本 |
5. 类型转换(避免踩坑)
| 功能分类 | MySQL 函数 | 示例/说明 | Oracle 对比 | 高频场景 |
|---|---|---|---|---|
| 隐式转换 | CAST(expr AS type) |
CAST('123' AS SIGNED) |
TO_NUMBER / TO_CHAR |
类型匹配防止SQL错误 |
| 显式转换 (简便) | 直接加 +0 |
ORDER BY score+0 |
- | 字符串字段按数值排序 |
6. 窗口函数(进阶必备,MySQL 8.0+)
| 功能分类 | MySQL 函数 | 示例/说明 | Oracle 对比 | 高频场景 |
|---|---|---|---|---|
| 排名 | ROW_NUMBER() , RANK() , DENSE_RANK() |
分组内排序编号 | 同MySQL | 排名类题目 -> 最核心解法 |
| 前后取值 | LAG(expr, offset) , LEAD(expr, offset) |
访问当前行之前/之后的行数据 | 同MySQL | 环比计算、差值分析 |
💡 刷题快速适应技巧
除了记函数,理解以下两点能避免很多"莫名奇妙"的错误:
-
NULL不参与运算 :在 MySQL 中,任何包含NULL的算术表达式结果都是NULL。例如salary + NULL的结果是NULL。如果你想忽略NULL继续计算,必须用IFNULL()将其转为 0。 -
字符串拼接别用
||:Oracle 中用||拼接字符串,但在 MySQL 的默认模式下,'a' || 'b'的结果是0(因为||被视为逻辑或运算符)。一定要用CONCAT('a', 'b')函数。 -
日期减法要小心 :在 Oracle 中
date1 - date2直接返回天数,但在 MySQL 中这样写返回的是数字,但逻辑有时不直观。建议统一使用DATEDIFF(date1, date2),这是最稳妥的做法。 -
TOP-N 查询写法不同 :Oracle 用
ROWNUM <= 10取前几条,MySQL 必须用LIMIT n放在ORDER BY后面,例如ORDER BY score DESC LIMIT 3。
DATE_FORMAT('2025-05-12, '%Y-%m') 为什么里面的Y是大写,m是小写
这是 MySQL 继承自 C 语言 strftime() 函数的标准格式 ,大小写分别代表不同的含义,不是随意设计的。
为什么 Y 大写,m 小写?
核心原因是:大写和小写代表不同的日期/时间部分,互不冲突。
| 格式符 | 含义 | 示例输出 | 为什么是这个大小写? |
|---|---|---|---|
%Y |
四位年份 (Year) | 2025 |
Y 大写 → 完整的、长格式的年份 |
%y |
两位年份 | 25 |
y 小写 → 简短、缩写形式的年份 |
%M |
完整的月份名称 (Month) | May |
M 大写 → 月份名称 (长) |
%m |
月份数字 (01-12) | 05 |
m 小写 → 月份数字 (短) |
%D |
带英文后缀的日期 | 12th |
D 大写 → 带序数词的完整格式 |
%d |
日期数字 (01-31) | 12 |
d 小写 → 纯数字格式 |
这样设计的 2 个核心好处
-
一个字母表达多种格式
用大小写区分,不需要发明两个不同的字母。例如
Y和y共享字母Y,通过大小写告诉 MySQL 你要4位 还是2位年份。 -
月份和分钟不冲突
月份(Month)和分钟(Minute)如果都用
m就乱套了。所以:-
%m= 月份 (Month) -
%i= 分钟 (Minute) --- 注意,分钟用的不是m,而是i,彻底避开冲突。
-
最容易混淆的 3 个例子(刷题必看)
| 你可能想当然的写法 | 实际正确写法 | 输出结果 | 错在哪 |
|---|---|---|---|
DATE_FORMAT(date, '%Y-%m') |
✅ '%Y-%m' |
2025-05 |
正确 ,Y大写四位年份,m小写月份数字 |
DATE_FORMAT(date, '%y-%M') |
❌ 不符合需求 | 25-May |
y小写→两位年份,M大写→完整月份名 |
想获取 May 12, 2025 |
'%M %d, %Y' |
May 12, 2025 |
月份名称用大写 M,日期数字用小写 d |
一个记忆技巧(不用硬背)
-
年份 :你想要长(4位)还是短(2位)?
长 → 大写 Y --- 因为
Y看起来很"大"短 → 小写 y --- 因为
y看起来很"小" -
月份 :你想看到英文单词(长)还是数字(短)?
英文单词 → 大写 M --- 因为单词比数字长
数字 → 小写 m --- 因为数字短小
-
分钟 :分钟 ≠ 月份 → 用
i(取 minute 里不冲突的字母 i)
实战建议
刷xxx题目时,不用背全表,记住最常用的这 3 个模式就够了:
sql
sql
-- 1. 按年月分组统计 (最常见)
DATE_FORMAT(create_time, '%Y-%m') -- 2025-05
-- 2. 按年月日分组
DATE_FORMAT(create_time, '%Y-%m-%d') -- 2025-05-12
-- 3. 只取月份数字
MONTH(create_time) -- 更简单
MONTH(date) 返回的是1,2,3 还是01,02,03呢
返回的是纯数字 1, 2, 3,不会补零。
验证一下
sql
SELECT MONTH('2025-05-12') -- 返回 5(没有前导0)
SELECT MONTH('2025-01-01') -- 返回 1(不是01)
和 DATE_FORMAT 的对比
| 函数 | 输入 2025-05-12 |
返回结果 | 类型 | 补零? |
|---|---|---|---|---|
MONTH(date) |
2025-05-12 |
5 |
整数 | ❌ 不补零 |
DATE_FORMAT(date, '%m') |
2025-05-12 |
05 |
字符串 | ✅ 补零 |
刷题时的影响
这个差异在以下场景会踩坑:
❌ 错误示例(以为 MONTH 返回字符串)
sql
-- 想把 5 和 '05' 拼接,结果不符合预期
SELECT CONCAT('月份是:', MONTH('2025-05-12')) -- 返回 '月份是:5'(不是 '月份是:05')
✅ 正确做法
场景1:需要补零的显示格式
sql
-- 用 DATE_FORMAT
SELECT DATE_FORMAT('2025-05-12', '%m') -- '05'
-- 或者手动补零
SELECT LPAD(MONTH('2025-05-12'), 2, '0') -- '05'
场景2:数值比较(直接相等判断)
sql
-- ✅ MONTH 可以直接和数字比较
WHERE MONTH(create_time) = 5 -- 正确
-- ❌ 但别和字符串 '05' 比较(虽然 MySQL 会隐式转换,但不规范)
WHERE MONTH(create_time) = '05' -- 能运行但不好
场景3:分组统计(不影响)
sql
-- ✅ 按月份分组,MONTH 返回 1-12,完全够用
SELECT MONTH(order_date), COUNT(*)
FROM orders
GROUP BY MONTH(order_date) -- 分组正确,不需要补零
一个记忆技巧
-
MONTH()→ 返回 数字类型 (用于计算、比较、分组)→ 不补零 -
DATE_FORMAT(..., '%m')→ 返回 字符串类型 (用于显示、拼接)→ 补零
快速对比例(方便记)
| 需求 | 用哪个函数 | 示例 |
|---|---|---|
| 筛选 5 月的订单 | MONTH(date) = 5 |
WHERE MONTH(order_date) = 5 |
| 按月份分组统计 | GROUP BY MONTH(date) |
GROUP BY MONTH(create_time) |
显示成 05 月 |
DATE_FORMAT(date, '%m') |
SELECT DATE_FORMAT(order_date, '%m') |
拼接成 2025-05 |
DATE_FORMAT(date, '%Y-%m') |
SELECT DATE_FORMAT(order_date, '%Y-%m') |
一句话总结 :MONTH() 返回纯数字 1-12 ;想要带前导零的 01-12,必须用 DATE_FORMAT(date, '%m')。
DATEDIFF(date1, date2)对其中的date1和date2的日期格式有要求吗,比如都带时分秒,或者不能有时分秒
没有严格要求 ,但建议 统一使用日期格式或只取日期部分,否则容易踩坑。
核心原理
DATEDIFF(date1, date2) 内部会自动提取日期部分,忽略时间(时分秒)。所以:
-
✅ 格式不同也能正常计算
-
✅ 带不带时分秒都可以
-
⚠️ 但字符串格式错误会导致报错
各种情况实测
| date1 | date2 | 结果 | 说明 |
|---|---|---|---|
'2025-05-12' |
'2025-05-10' |
2 |
✅ 标准日期格式 |
'2025-05-12 23:59:59' |
'2025-05-10 00:00:00' |
2 |
✅ 自动忽略时分秒 |
'2025-05-12 23:59:59' |
'2025-05-12 00:00:01' |
0 |
✅ 同一天,时分秒不影响 |
'2025-05-12' |
'2025-05-10 18:30:00' |
2 |
✅ 混合格式也可以 |
'20250512' |
'20250510' |
2 |
✅ 纯数字字符串也能识别 |
'2025/05/12' |
'2025/05/10' |
2 |
✅ 斜杠分隔也能识别 |
'12-05-2025' |
'10-05-2025' |
❌ NULL |
❌ 非标准顺序会失败 |
3 个容易踩的坑
坑1:字符串格式不标准导致报错或 NULL
sql
-- ❌ 错误:日期的顺序不对
SELECT DATEDIFF('12-05-2025', '10-05-2025'); -- 可能返回 NULL 或报错
-- ✅ 正确:使用标准格式 YYYY-MM-DD
SELECT DATEDIFF('2025-05-12', '2025-05-10'); -- 2
坑2:以为时间会影响结果(实际不会)
sql
-- 虽然是同一天的不同时间,但 DATEDIFF 只看日期
SELECT DATEDIFF('2025-05-12 23:59:59', '2025-05-12 00:00:01'); -- 0(不是 1)
-- 如果真要按时间差计算天数,用 TIMESTAMPDIFF
SELECT TIMESTAMPDIFF(DAY, '2025-05-12 00:00:01', '2025-05-12 23:59:59'); -- 0(还是0,因为不足24小时)
SELECT TIMESTAMPDIFF(HOUR, '2025-05-12 00:00:01', '2025-05-12 23:59:59'); -- 23
坑3:字段类型是 DATETIME 但直接传字符串格式错误
sql
-- 假设表中 create_time 是 DATETIME 类型
-- ❌ 错误比较(字符串格式不对)
SELECT DATEDIFF(create_time, '12-05-2025') FROM orders; -- 可能 NULL
-- ✅ 正确:用标准格式字符串
SELECT DATEDIFF(create_time, '2025-05-12') FROM orders; -- 正常计算
-- ✅ 或者直接用字段(最安全)
SELECT DATEDIFF(create_time, '2025-05-12') FROM orders; -- create_time 会自动提取日期部分
刷题最佳实践
🎯 安全写法(推荐)
sql
-- 1. 字段已经是日期/时间类型,直接使用
SELECT DATEDIFF(order_date, pay_date) FROM orders;
-- 2. 字符串日期统一转为标准格式
SELECT DATEDIFF('2025-05-12', '2025-05-10');
-- 3. 如果字段有时分秒,想按真实时间差(精确到24小时)用 TIMESTAMPDIFF
SELECT TIMESTAMPDIFF(DAY, '2025-05-12 00:00:01', '2025-05-13 00:00:00'); -- 0(不足24小时)
SELECT TIMESTAMPDIFF(HOUR, '2025-05-12 00:00:01', '2025-05-13 00:00:00'); -- 23
📝 xxx典型题目示例
sql
-- 题目:计算用户下单到支付的天数
-- 表 orders: order_date (DATETIME), pay_date (DATETIME)
-- ✅ 直接用 DATEDIFF(自动忽略时分秒)
SELECT
order_id,
DATEDIFF(pay_date, order_date) AS pay_days
FROM orders;
-- 如果题目要求"超过24小时才算1天",那就不能用 DATEDIFF
-- 改用 TIMESTAMPDIFF
SELECT
order_id,
TIMESTAMPDIFF(DAY, order_date, pay_date) AS pay_days
FROM orders;
快速记忆
| 需求 | 用什么 | 示例 |
|---|---|---|
| 按日历日期算差(忽略时间) | DATEDIFF(date1, date2) |
DATEDIFF('2025-05-12 23:59', '2025-05-11 00:00') → 1 |
| 按24小时时间差算 | TIMESTAMPDIFF(DAY, dt1, dt2) |
TIMESTAMPDIFF(DAY, '2025-05-11 23:59', '2025-05-12 00:00') → 0 |
| 安全的日期字符串格式 | 'YYYY-MM-DD' |
'2025-05-12'(最稳妥) |
一句话总结 :DATEDIFF 对格式宽容但有限制 ,只要 MySQL 能识别成有效日期(推荐 YYYY-MM-DD),无论带不带时分秒都能正确计算;非标准顺序(如 DD-MM-YYYY)会直接报错或返回 NULL。