很多人把 MySQL 装好之后,第一道坎根本不是建表,而是写 SELECT 时被各种各样的 MySQL 函数搞晕。字符串要截取、日期要格式化、数字要四舍五入、空值要处理、排名要分组,每一件事都对应一批函数,而且名字还长得特别像。网上搜"MySQL 函数",出来的资料要么是官方文档那种干巴巴的语法清单,要么是碎片化的速查表,真正能让人看完会用的很少。所以我打算按实际干活时的思路,把最常用、最容易踩坑的这批函数完整梳理一遍,顺带把新手问得最多的几个问题——SUBSTRING 和 SUBSTR 有什么区别、ROUND 为什么不是我以为的结果、DATE_FORMAT 里 %Y 和 %y 是不是一个意思、有没有函数叫 sub_str——一次性说清楚。这篇文章适合刚学 MySQL 的人、准备数据库面试的开发,以及平时写统计报表被数据折磨的运营和数据分析同学。
1. 函数正式写进SQL之前,先拨正三组概念
网上搜"select函数"其实搜不到任何东西,因为 SELECT 是 SQL 的查询语句,不是函数。这个误区看起来很低级,但每天都有人在搜索引擎里敲,说明很多初学者把"SQL 里的关键字"和"函数"混在一起了。抛开这一点,我更想强调另外三组概念,它们决定了你后面能不能顺畅理解和使用函数。
1.1 函数、关键字和操作符,三者不是一回事
SQL 里有三样东西经常被混着叫,但性质完全不同:
- 关键字/语句:SELECT、FROM、WHERE、GROUP BY、ORDER BY,这些是 SQL 的骨架,不是一个值,也没有返回值。
- 操作符:+、-、*、/、=、>、LIKE,这些是运算符号,通常操作两个值。
- 函数:CONCAT、IF、DATE_FORMAT、ROUND,它们接收输入参数,经过内部逻辑处理后返回一个值。
判断一个东西是不是函数,最简单的办法是看它能不能单独出现在 SELECT 后面。SELECT SUBSTRING('abc',1,2) 能出来结果,所以 SUBSTRING 是函数。SELECT WHERE 会直接语法报错,所以 WHERE 只是语句的一部分。很多所谓"函数记不住"的问题,其实是根本没意识到自己只是需要某个操作符或者语句组合。
1.2 内置函数、自定义函数和存储过程别混用
MySQL 内置函数是数据库自带的,直接写名字就能用。自定义函数(CREATE FUNCTION)是你在库里创建的一个可复用的逻辑块,语法和内置函数类似,但写起来要定义返回类型、函数体,通常还用 BEGIN...END 包裹。存储过程(CREATE PROCEDURE)则更进一步,它可以包含多条 SQL、事务、游标、循环,有入参和出参,但调用时用的是 CALL 而不是写在 SELECT 里。
我见过不少人把存储过程和函数混为一谈,实际工作中我们的建议很简单:单行数据处理优先用内置函数,需要大量循环和事务逻辑才考虑存储过程,自定义函数能不用就不用——它一旦被查询引用,往往会让 MySQL 优化器难以预估成本,排查问题时多一层复杂度。
1.3 函数能出现在 SQL 的哪些位置
函数不是只能放在 SELECT 后面。这是很多基础教程讲得不透的地方。一个函数可以出现在:
- SELECT 后面:SELECT UPPER(name) FROM users,用来计算输出值。
- WHERE 后面:SELECT * FROM users WHERE CHAR_LENGTH(phone) = 11,用来过滤行。
- GROUP BY 后面:SELECT DATE(create_time), COUNT(*) FROM orders GROUP BY DATE(create_time),用来按函数处理后的结果分组。
- HAVING 后面:SELECT user_id, SUM(amount) FROM orders GROUP BY user_id HAVING SUM(amount) > 1000,作用类似于 WHERE,但作用于分组后。
- ORDER BY 后面:SELECT * FROM products ORDER BY LENGTH(name) DESC,按函数计算结果排序。
同一个函数放在不同位置,性能含义完全不同。尤其 WHERE 里包函数,极容易让索引失效,后面第 8 节我会专门讲。这里大家先建立位置意识,写 SQL 时脑子里过一遍:这个函数我放在哪,它对索引有没有影响。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 字符串函数:解析、拼接与截断的日常操作
字符串处理占了我日常 SQL 编写量的一半以上。分类、去空格、提取子串、拼接字段、替换关键词,样样都绕不开字符串函数。
2.1 SUBSTRING、SUBSTR 和 sub_str 的纠葛
先澄清一个搜索热词:sub_str 函数。MySQL 里根本没有 sub_str 这个函数,正确答案是 SUBSTRING,它有一个同义词 SUBSTR。很多人搜不到,是因为下意识按"下划线缩写"的方式去猜函数名,但 MySQL 函数名不是这样缩写出来的。
SUBSTRING 的三种写法:
mysql复制SELECT SUBSTRING('hello world', 5); -- 从第5个字符开始截到末尾,结果是 'o world'
SELECT SUBSTRING('hello world', 1, 3); -- 从第1个字符开始截3位,结果是 'hel'
SELECT SUBSTRING('hello world', -5, 3); -- 从倒数第5位开始截3位,结果是 'wor'
这里的起始位置从 1 开始,不是像编程语言那样从 0 开始。支持负数表示从尾部倒数。这个函数虽然叫 SUBSTRING,但它按字符截取,不按字节截取,所以处理多语言内容时比很多编程语言的 substring 更友好。
2.2 LOCATE、LEFT、RIGHT、SUBSTRING_INDEX 的组合用法
实际工作中很少直接傻写一个固定长度的 SUBSTRING,因为真实数据的长短不固定。更常见的思路是先定位、再截取。
LOCATE(substr, str) 返回 substr 在 str 中第一次出现的位置。比如 LOCATE('@', 'zhangsan@qq.com') 返回 9。INSTR 和 POSITION 也能做类似的事,但参数顺序不同:
mysql复制SELECT LOCATE('@', 'zhangsan@qq.com'); -- 9
SELECT INSTR('zhangsan@qq.com', '@'); -- 9
SELECT POSITION('@' IN 'zhangsan@qq.com') ; -- 9
LEFT 和 RIGHT 分别是取字符串左边和右边固定长度的子串。LEFT('2024-11-15', 4) 结果是 2024,RIGHT('13812345678', 4) 结果是 5678。这个在取编号、截手机号尾号时很好用。
SUBSTRING_INDEX 是个被低估的强函数。它按分隔符截取,语法是 SUBSTRING_INDEX(str, delimiter, count),count 为正数时从左往右数到第 count 个分隔符返回左边全部内容,count 为负数时从右往左数到第 count 个分隔符返回右边全部内容:
mysql复制SELECT SUBSTRING_INDEX('a,b,c,d', ',', 2); -- 'a,b'
SELECT SUBSTRING_INDEX('a,b,c,d', ',', -2);
