今天,我们来共同学习 MySQL 数据库中一些鲜为人知但功能强大的内置函数,包括 RAND() 函数、IFNULL() 函数和 WITH ROLLUP() 函数。掌握这些十分实用却又容易被忽略的内置函数,它们不仅能提升你的 SQL 查询效率,而且是一条非常有效的 SQL 老手进阶途径。
在开始学习之前,设想这样一个情境:你是一家互联网公司数据部门的后端开发者,产品经理需要你从 MySQL 数据库中提取一些员工数据。现在,让我们看看如何以简洁高效的方式满足产品经理的需求。
RAND() 函数:返回随机数
产品经理的第一个问题是,他要采样一些员工信息做报表用,让你帮他随机抽取 5 条员工信息。这个需求的难点,就在于 抽取的方法是随机的。
对于这个问题你可能会想,直接用 LIMIT 5 不就解决了吗?但问题就在于,LIMIT 5 操作只是限定返回的行数,不具备随机性,所以是不符合查询需求的。
其实,在 MySQL 中有个 内置函数 RAND() 可以返回 0~1 之间的随机数。我们利用这个内置函数,就可以对结果数据进行随机排序。于是,我们可以在 MySQL 命令行中写出下面这个 SELECT 语句:
代码语言:sql复制SELECT emp_no,birth_date,first_name,last_name,hire_date FROM EMPLOYEE ORDER BY RAND() LIMIT 5;
很快 MySQL 命令行就能列出随机抽取的 5 条员工数据,你可以看一下:
代码语言:sql复制 -------- ------------ ------------ ----------- ------------
| emp_no | birth_date | first_name | last_name | hire_date |
-------- ------------ ------------ ----------- ------------
| 495223 | 1960-01-08 | KayLiang | Bisiani | 1985-06-18 |
| 92234 | 1956-08-07 | Georg | Hofman | 1989-07-12 |
| 41230 | 1955-09-13 | Adly | Schieder | 1989-10-18 |
| 272876 | 1952-02-29 | Aamer | Standera | 1985-12-30 |
| 499069 | 1963-06-22 | Kersti | Hegner | 1988-11-24 |
-------- ------------ ------------ ----------- ------------
现在,我们来分析一下 ORDER BY RAND() 的执行过程:MySQL 首先会给每行数据生成一个 0~1 之间的随机数,然后将查询出的结果数据按这个随机数的大小排序,最后返回排序数据中的前 5 条。
我需要提醒你的是, 在数据量大的表上执行 ORDER BY RAND() 的效率较低,需要寻求其他的随机取数方案。
IFNULL() 函数:对 NULL 字段赋默认值
产品经理对于随机抽取的员工信息感到满意,但他还有进一步的需求。他希望查看部分员工的生日信息,如果生日字段为空,则需要显示“保密,未提供”。
这个问题的关键点就在于,没有生日信息时需要将生日信息 显示为特定的字符。你可能比较容易想到用 CASE WHEN 来解决,但 CASE WHEN 的语法稍显冗长。
其实 内置函数 IFNULL(e1,e2) 也能完成这个功能,而且更加方便。它会接收两个参数,当第一个参数不为 NULL 时就返回第一个参数,否则返回第二个参数。利用这个函数,你就能用下面这个简洁的 SQL 拿到产品经理需要的数据了:
代码语言:sql复制SELECT emp_no,IFNULL(birth_date,'保密,未提供') AS birth_date FROM employee LIMIT 5;
可以看到,结果中那些值为 NULL 的 birth_date 已经自动替换为了“保密,未提供”字样:
代码语言:sql复制 -------- --------------------
| emp_no | birth_date |
-------- --------------------
| 10001 | 保密,未提供 |
| 10002 | 1964-06-02 |
| 10003 | 保密,未提供 |
| 10004 | 1954-05-01 |
| 10005 | 1955-01-21 |
-------- --------------------
从这个例子中,可以看到使用了 IFNULL() 函数后,你的 SQL 语句变得清晰简洁。
WITH ROLLUP 操作:对分组统计指标做总的统计
在你稍作休息时,产品经理又提出了新的要求,他希望查看每位员工任职期间的平均薪资,同时还要了解所有员工的平均薪资。这时,你可能想到薪水表 salary 中存放的是每个员工不同任职阶段的薪水情况,根据员工号 GROUP BY 分组之后,每组对薪水字段求平均值即可。可是产品经理希望同时获取所有员工的平均薪资,这是一个比较麻烦的点。
于是你翻看 GROUP BY 的使用说明,发现它可以配合一个 WITH ROLLUP 操作,这个操作能让你在分组计算的基础上再对每组的统计指标进行整体的统计,这不就能实现产品经理的同时查所有员工平均薪水的要求了吗?于是,你很快就写下了带有额外整体统计的分组查询 SQL:
代码语言:sql复制SELECT emp_no,AVG(salary) FROM salary GROUP BY emp_no WITH ROLLUP;
结果也如你预期的那样,除了有每位员工在各个任职阶段的平均薪水外,还在最后一行列出了所有员工的平均薪水:
代码语言:sql复制 -------- -------------
| emp_no | avg(salary) |
-------- -------------
| 10001 | 75388.9412 |
| 10002 | 68854.5000 |
...
| 499999 | 70625.0000 |
| NULL | 63810.7448 |
-------- -------------
由于最后一行是整体的平均值,所以它不属于任何一个员工,于是在员工号这一列出现了 NULL 值。结合咱们刚刚讲到的 内置函数 IFNULL(),你能够很方便地将这个 NULL 值显示为特定内容的,比如显示为“员工平均薪水”。这样,你提供的数据也会超出他的预期。到这里,你在整个过程中查询出了所有关键的数据。产品经理根据这些数据,就能出具一份漂亮的员工信息报表啦。
总结
让我们来回顾一下今天的内容。通过一个实际的应用场景,我们介绍了三个 MySQL 内置函数:
- 使用
RAND()
函数实现数据的随机抽取。 - 利用
IFNULL()
函数为 NULL 字段设置默认值。 - 通过
WITH ROLLUP
操作对分组统计进行总体统计。
这些内置函数只是 MySQL 查询技巧的冰山一角。在实际工作中,还有许多其他内置函数,如NULLIF()
、COALESCE()
等,可以帮助你简化 SQL 查询,提升查询效率。