2026/10/5 7:40:09

MySQL常用函数实战指南:从基础查询到数据处理,SQL效率倍增

MySQL常用函数实战指南:从基础查询到数据处理,SQL效率倍增 零基础学MySQL每个新手都会经历这样一个阶段表建好了数据插进去了SELECT * FROM xxx也能查出来了然后……就没有然后了。等真正接手业务需求要统计销售额、要按地区拼接地址、要把时间字段做成报表维度时突然发现SELECT和WHERE完全不够用。这时候你搜索出来的答案里十个有八个都在用函数。MySQL 常用函数就是把你从“能查数据”提升到“会处理数据”的那道分水岭。这篇文章不聊安装、不聊配置专门把 MySQL 里日常最高频的常用函数按场景拆开讲透每个函数都配上可以直接抄的案例和实际踩坑记录。内容适合两类人一类是刚入门、能写基础查询但遇到真实需求就卡壳的新手另一类是写了很多年 SQL、但一直靠现搜现抄、没系统梳理过函数体系的开发者。把这些函数拿捏住日常 80% 的数据处理需求都不在话下。1. 为什么说常用函数是提升SQL效率的利器1.1 函数的本质与SQL执行逻辑函数本质上就是一个“黑匣子”你给它一个或多个输入它按固定规则处理完给你一个确定的输出。SQL 里写函数就是在数据流动的过程中加一层处理逻辑。听起来很简单但很多人恰恰忽略了“数据流动”这四个字导致对函数的使用时机和位置判断不准。我见过不少零基础同学陷入一个误区觉得只要能查出数据就行函数这种东西等要用的时候再查。这个想法会让人长期停留在“复制粘贴”阶段。真实业务里几乎没有“直接查出来就能用”的数据永远要清洗、要格式化、要计算、要汇总。把常用函数当成工具箱里的常备工具而不是临时翻文档的应急品写 SQL 的效率和心态会完全不同。还需要理解函数出现的几个位置。在 MySQL 里函数可以用在SELECT后面影响结果展示也可以用在WHERE后面影响行过滤还可以用在ORDER BY、GROUP BY、HAVING后面影响排序和分组统计。不同位置处理的阶段不同比如WHERE过滤发生在分组之前HAVING过滤发生在分组之后同一个函数放在不同位置业务含义完全不一样。把这个先后顺序理清楚函数才算真的用活了。1.2 常用函数分类总览MySQL 官方文档里的函数数量非常多零基础没必要全背。我把日常实际使用频率最高的函数归成几个大类每类记住几个核心函数就能覆盖绝大多数业务场景。函数类别核心函数典型用途字符串函数CONCAT、SUBSTRING、REPLACE、TRIM、UPPER、LOWER、LEFT、RIGHT拼接、截取、清洗、格式化文本数值函数ROUND、CEIL、FLOOR、ABS、MOD小数处理、取整、绝对值、取余日期时间函数NOW、DATE_FORMAT、DATEDIFF、DATE_ADD、YEAR、MONTH获取当前时间、格式化、日期差值计算条件逻辑函数IF、IFNULL、CASE WHEN按条件返回不同值、空值兜底聚合函数COUNT、SUM、AVG、MAX、MIN分组汇总、统计全局数据这个分类不是官方标准而是我自己的使用经验总结。像类型转换函数CAST、CONVERT也很常用但对零基础来说可以晚点再学遇到具体报错再回来补效果往往更好。后面的章节我会按这个顺序逐个展开每个函数都会讲清楚“是什么、怎么用、坑在哪”。2. 字符串函数数据清洗与格式化的第一课字符串函数是大部分人接触到的第一类函数因为它最直观而且几乎所有业务都离不开文本处理。用户姓名拼接、手机号打码、商品编码截取全是字符串函数的活。2.1 拼接与截取CONCAT、SUBSTRING、LEFT、RIGHTCONCAT是使用频率最高的字符串函数之一作用是把两个或多个字符串拼成一个。实际业务里最常见的用法是把用户姓名和部门拼到一起展示或者拼接完整地址。SELECT CONCAT(张, 三, 同学) AS full_name; -- 输出张三同学 SELECT CONCAT(emp_name, - , dept_name) AS emp_info FROM employee;这里有一个大坑必须提醒CONCAT 遇到任何一个参数为 NULL整个结果就是 NULL。我之前给业务方导用户地址拼完发现大量行为 NULL排查了很久才发现是部分用户的 district 字段为空。所以写拼接 SQL 之前一定先确认源头字段是否有 NULL有就用IFNULL或COALESCE兜底SELECT CONCAT(IFNULL(province, ), IFNULL(city, )) AS full_address FROM user_info;提示CONCAT 遇 NULL 即 NULL这是新手最容易踩的坑之一。拼接前先用 IFNULL 或 COALESCE 做好兜底别等到结果全是 NULL 才发现。再来是截取函数。SUBSTRING(字符串, 起始位置, 长度)用得最多经典场景是从身份证号里截取出生日期。注意 MySQL 的字符串位置从 1 开始不是 0。第一次用的时候如果发现结果少了一位十有八九是下标问题。SELECT SUBSTRING(id_card, 7, 8) AS birth_date FROM user_info;LEFT和RIGHT就简单得多一个从左边截 N 个字符一个从右边截 N 个字符。比如商品编码左边两位是分类编码直接LEFT(code, 2)就能取出来手机号后四位做安全展示用RIGHT(phone, 4)。这类函数一眼就能看懂但胜在写起来简洁比SUBSTRING少写一个参数我用得很频繁。2.2 替换、去空格与大小写REPLACE、TRIM、UPPER、LOWER从外部导入的数据最烦的就是字段里混着空格、换行或者大小写不统一。REPLACE(列名, 要找的, 替换成)专门干这个活。比如手机号里有横杠直接替换掉分类名称里“旧版”要统一改成“经典版”也可以用UPDATE配合REPLACE批量处理。-- 去掉手机号里的横杠 SELECT REPLACE(phone, -, ) FROM user_info; -- 把分类名称里的“旧版”统一改成“经典版” UPDATE product SET category REPLACE(category, 旧版, 经典版);TRIM是去两端空格函数也能去掉指定字符。别小看它从 Excel 导入的数据里经常带肉眼看不见的空格直接导致WHERE name 张三匹配不到数据。遇到这种诡异问题先对字段做一次TRIM再比较就好了。TRIM(BOTH - FROM --abc--)还能把首尾的横杠去掉处理用户输入的脏数据时很实用。SELECT TRIM(name) FROM user_info; -- 去掉字符串首尾的指定符号 SELECT TRIM(BOTH - FROM --abc--);UPPER和LOWER是大小写转换。用户注册时可能输入大小写混合的邮箱统计的时候统一LOWER一下再分组、去重结果才会干净。不过需要提醒一句如果在WHERE条件里对索引列使用函数可能会导致索引失效。数据量小的时候没感觉数据量大了查询会明显变慢。我的习惯是能不用函数就不在索引列上用函数或者想办法在条件右侧用函数减少对索引列的影响。3. 数值处理与条件逻辑计算和判断省心省力字符串处理完了接下来是数值和条件逻辑。这类函数看起来简单但用好之后能让单个 SQL 的计算密度高很多原本要在程序里写循环判断的逻辑一条 SQL 就搞定了。3.1 小数处理与符号运算ROUND、CEIL、FLOOR、ABS、MODROUND是四舍五入CEIL是向上取整FLOOR是向下取整这三个的区别一定要分清。做价格展示的时候特别典型商品价格 19.8 元保留一位小数是 19.8向上取整变 20向下取整变 19。SELECT price, ROUND(price, 1) AS round_1, CEIL(price) AS ceil_price, FLOOR(price) AS floor_price FROM product;ROUND的第二个参数表示保留几位小数可省略默认保留 0 位。做金额计算时我建议明确写出来因为ROUND(2.5)在 MySQL 里的结果是 3有些数据库却返回 2跨库迁移容易踩坑。ABS是绝对值MOD是取余数。判断奇偶、分库分表取模、算两个账户金额差异的绝对值都是这两个函数的经典场景。-- 判断订单号奇偶奇数走 A 通道处理 SELECT order_id, MOD(order_id, 2) AS channel FROM orders; -- 取两个账号金额差异的绝对值 SELECT ABS(acct1_balance - acct2_balance) AS diff FROM accounts;数值函数看着简单最容易出问题的是精度。货币金额我强烈建议用DECIMAL类型计算完再ROUND如果用FLOAT或DOUBLE算很容易出现 0.30000000000000004 这种结果对账场景下会出大事。这个坑我在刚做电商对账时踩过深有体会。3.2 条件判断函数IF、IFNULL、CASE WHENIF(条件, 真值, 假值)是 SQL 里的三元表达式结构简单但非常实用。比如判断订单金额是否超过 1000直接打标签SELECT order_id, total_amount, IF(total_amount 1000, 大单, 普通单) AS order_type FROM orders;IFNULL(expr, 默认值)专门处理 NULL如果 expr 是 NULL返回默认值否则返回 expr 本身。很多初学者分不清IFNULL和IF的区别其实一个是空值兜底一个是条件判断用途完全不同。还有个类似函数叫COALESCE可以传多个参数返回第一个非 NULL 的值在多字段兜底时比IFNULL好用得多SELECT COALESCE(phone, mobile, 无联系方式) AS contact FROM user_info;CASE WHEN是 SQL 里最强大的条件表达式没有之一。IF只能处理一个条件CASE WHEN可以写多个分支逻辑清晰、易维护。面试和实际业务里都爱考。比如把订单按金额分成多个等级SELECT order_id, total_amount, CASE WHEN total_amount 100 THEN 小额订单 WHEN total_amount 1000 THEN 中额订单 WHEN total_amount 5000 THEN 大额订单 ELSE 超大额订单 END AS order_level FROM orders;CASE WHEN的判定顺序是从上往下一旦命中就会跳出不再往下匹配。所以写条件时要从范围小的往范围大的写或者确保条件互斥。我有一次把total_amount 1000写在前面结果所有超千订单全被算进了“大额”后面的分支根本走不到最后只能重跑任务。还有一个细节END后面一定记得写列别名不然查询结果里那列表头会是一长串表达式程序里引用时非常难受。4. 日期时间函数业务统计里永远绕不开的坑日期时间是 SQL 里最容易出错、也最有价值的一类函数。业务报表按天、按月、按年统计全靠日期函数转换和分组。零基础同学通常觉得日期函数数量太多、记不住。我建议先记最常用的几个用多了自然就熟练了。4.1 获取当前时间与时间戳转换获取当前时间有三个高频函数NOW()返回完整日期时间CURDATE()只返回日期部分CURTIME()只返回时间部分。还有一个细节NOW()在同一个查询里多次调用返回的是同一个时间点SYSDATE()则不同每次调用都可能变化。这个差异很小但某些对时间一致性要求高的场景会踩到。SELECT NOW() AS current_datetime, CURDATE() AS current_date, CURTIME() AS current_time;时间戳转换在对接第三方数据时非常常见。UNIX_TIMESTAMP把日期时间转成秒级时间戳FROM_UNIXTIME把秒级时间戳转回可读日期。很多接口返回的就是时间戳而数据库里存的是日期时间这两个函数就是桥。SELECT UNIX_TIMESTAMP(2024-06-01 12:00:00); -- 输出秒级时间戳 SELECT FROM_UNIXTIME(1717214400); -- 输出可读日期时间4.2 格式化、差值计算与日期偏移DATE_FORMAT是日期函数里的“门面”把日期时间按指定格式重新包装。业务报表用得最多的是按月分组统计SELECT DATE_FORMAT(create_time, %Y-%m) AS month, COUNT(*) AS order_cnt FROM orders GROUP BY DATE_FORMAT(create_time, %Y-%m) ORDER BY month;格式化符号一定要记牢%Y是四位年%y是两位年%m是两位月%d是两位日%H是 24 小时制小时%i是分钟%s是秒。容易混淆的是%Y和%y、%H和%h后者是 12 小时制。如果格式化结果不对先检查符号是否写对我经常看到有人把%m当成分钟用查半天才发现是符号理解错了。DATEDIFF(结束日期, 开始日期)计算两个日期相差的天数在会员有效期、订单超时判断里很常用。DATE_ADD和DATE_SUB是日期偏移函数第二个参数用INTERVAL加上时间量。计算最近 30 天的数据范围是最典型场景SELECT DATE_SUB(CURDATE(), INTERVAL 30 DAY) AS start_date, CURDATE() AS end_date;INTERVAL支持的单位很丰富DAY、MONTH、YEAR、HOUR、MINUTE、SECOND都行。做定时任务或滑动窗口统计时这组函数非常好使。这里还有一个使用心得日期函数几乎都会受时区影响线上数据库时区和服务器时区不一致拿到“当前时间”可能和业务方实际时间差好几个小时。如果业务对时间敏感建议统一用数据库所在时区或者干脆存 UTC 时间展示层再转换这样最稳。5. 聚合函数与分组统计从“看单条”到“看全局”前面讲的函数都是对单行数据做处理聚合函数则完全不同它把多行数据合并成一个结果。这种“从单条到全局”的思路转变是 SQL 进阶的重要一步也是报表统计的基础。5.1 COUNT、SUM、AVG、MAX、MIN的适用场景五个核心聚合函数COUNT统计行数SUM求和AVG求平均MAX取最大MIN取最小。别看名字简单细节非常多面试里最爱问的就是这些“听起来简单”的函数。SELECT COUNT(*) AS total_cnt, COUNT(user_id) AS valid_user_cnt, SUM(amount) AS total_amount, AVG(amount) AS avg_amount, MAX(amount) AS max_amount, MIN(amount) AS min_amount FROM orders;COUNT(*)和COUNT(列名)的区别是最大的坑。COUNT(*)统计所有行包括 NULL 所在行COUNT(列名)只统计该列非 NULL 的值的数量。比如统计用户表里的手机号数量如果直接用COUNT(phone)而手机号存在缺失结果比COUNT(*)少。你以为自己在统计用户总数实际上统计的是“有手机号的用户数”这种 bug 很隐蔽。SUM和AVG会自动忽略 NULL 值但整列全是 NULL 时SUM返回 NULL 而不是 0。AVG也一样不想看到 NULL 就用IFNULL兜底。MAX和MIN对字符串和数字都能比较但要注意类型一致性字符串比较按字典序来。还有一个高频操作是去重统计用COUNT(DISTINCT 列名)统计去重后的数量比如统计去重用户数这种“先想去重再想统计”的思路很实用。5.2 GROUP BY HAVING 的正确使用姿势GROUP BY是聚合函数的最佳搭档。先分组、再聚合是报表的基本逻辑。按部门统计人数是最经典的例子SELECT dept_id, COUNT(*) AS emp_cnt, AVG(salary) AS avg_salary FROM employee GROUP BY dept_id;GROUP BY有两个容易踩的坑。第一SELECT后面的非聚合列必须出现在GROUP BY里。MySQL 老版本对这个问题管得不严可能返回随机行的值但同样一条 SQL 放到 MySQL 8.0 或 PostgreSQL 里就直接报错。我见过不少同学靠着老版本 MySQL 的“宽容”写出不规范 SQL一旦迁移就崩所以从一开始就养成规范习惯很重要。第二WHERE和HAVING的区别。WHERE在分组之前过滤行HAVING在分组之后过滤组。看这个例子-- 筛选金额大于100的订单按用户汇总最后只看汇总金额超过500的用户 SELECT user_id, SUM(amount) AS total_amount FROM orders WHERE amount 100 GROUP BY user_id HAVING SUM(amount) 500;把HAVING里的条件误写到WHERE里比如WHERE SUM(amount) 500会直接报错因为执行WHERE时聚合结果还没出来。反过来把单行条件amount 100写在HAVING里虽然不报错但性能会差很多因为所有行都参与了分组聚合才被过滤。我优化过很多慢查询不少就是HAVING里塞了单字段条件移到WHERE后速度立马上来。6. 进阶组合技巧与常见问题排查基础函数学完之后还要学会组合使用。SQL 函数最大的价值恰恰在组合单个函数效果有限组合起来才能处理复杂业务需求。这一节分享几个我实际工作中高频使用的组合技巧顺手把新手最爱踩的坑整理成速查表。6.1 函数嵌套与GROUP_CONCAT的妙用函数嵌套就是把一个函数的结果作为另一个函数的输入。比如DATE_FORMAT和SUM配合可以按月汇总IF和COUNT配合可以做条件计数-- 统计每个品类下大额订单占比 SELECT category_id, COUNT(IF(total_amount 1000, 1, NULL)) AS big_order_cnt, COUNT(*) AS total_cnt, ROUND(COUNT(IF(total_amount 1000, 1, NULL)) / COUNT(*), 4) AS big_order_ratio FROM orders GROUP BY category_id;这个写法很常用。COUNT(IF(条件, 1, NULL))的意思是满足条件的行计为 1不满足置为 NULL而COUNT忽略 NULL所以统计结果就是满足条件的行数。注意这里不能写成COUNT(IF(条件, 1, 0))否则COUNT会把 0 一起数进去结果和COUNT(*)一样。GROUP_CONCAT是一个非常有用的函数能把分组内的多行数据拼成一个字符串。比如把每种技能对应的用户名列出来SELECT skill, GROUP_CONCAT(user_name ORDER BY user_id SEPARATOR 、) AS users FROM user_skill GROUP BY skill;GROUP_CONCAT有几个细节要记住SEPARATOR指定分隔符默认是逗号ORDER BY可以控制拼接顺序最坑的是默认最大长度只有 1024 字节超过会被截断。如果拼接结果不全先检查是不是长度超了可以用SET SESSION group_concat_max_len 102400调整。另外拼接时可以用DISTINCT去重比如GROUP_CONCAT(DISTINCT dept_name)避免重复项出现在结果里。6.2 常见问题速查表与避坑经验下面把这些阶段最常见的坑整理成速查表都是实际跑 SQL 时容易遇到的问题现象根本原因解决办法CONCAT 拼接结果出现 NULL某个参数字段为 NULL用 IFNULL 或 COALESCE 兜底COUNT 结果比预期少使用了 COUNT(列名) 而该列有 NULL明确统计意图必要时用 COUNT(*)GROUP BY 后选了不在分组里的列非聚合列未包含在 GROUP BY 中把该列加入 GROUP BY或改成聚合值单行条件写在 HAVING 里导致慢查询混淆了分组前后过滤单行条件移到 WHERE日期格式化结果不对%y 和 %Y、%h 和 %H 混淆检查格式化符号写法GROUP_CONCAT 结果被截断超过 1024 字节限制调整 group_concat_max_lenCASE WHEN 分支结果异常条件顺序写错先命中了小范围分支从小到大书写或保证条件互斥金额计算出现小数误差使用 FLOAT/DOUBLE 存储金额金额字段改 DECIMAL 类型查询结果出现奇怪数字隐式类型转换导致明确用 CAST 指定类型最后给一条贯穿所有函数的使用心法先看数据再写函数。写 SQL 之前先把字段的数据类型、有没有 NULL、数据格式是否统一摸清楚。不管函数多强大源头数据是乱的后面清洗起来都费劲。有个小伙伴写了个很长的 SQL用了六七个函数跑出来结果还是不对。我让他先把原始数据SELECT出来看一眼立刻就发现日期字段里混着0000-00-00和正常日期所有涉及日期计算的函数结果全是 NULL。数据源不干净函数写得再认真也是白搭。我个人带过不少零基础的同学最深的体会是MySQL 常用函数不是背出来的是一条查询一条查询“磨”出来的。别指望看完这篇文章就把所有函数记住这不现实。更靠谱的做法是今天先挑四个最常用的——CONCAT、ROUND、DATE_FORMAT、COUNT在自己业务数据上跑一遍跑通了再往下加。踩过的坑都会变成你的经验。等这些基础函数用顺手了再去碰窗口函数、存储过程这些高级特性会轻松很多。函数就是 SQL 的地基地基牢了后面学什么都踏实。