1.问题来源。
该问题来源于leetcode上面的一道mysql题目,619只出现一次的最大值。如果想要快速了解上述问题的原理及总结,请参见引文文章
摘录于下
MyNumbers 表:
+-------------+------+
| Column Name | Type |
+-------------+------+
| num | int |
+-------------+------+
该表可能包含重复项(换句话说,在SQL中,该表没有主键)。
这张表的每一行都含有一个整数。
单一数字 是在 MyNumbers 表中只出现一次的数字。
找出最大的 单一数字 。如果不存在 单一数字 ,则返回 null 。
查询结果如下例所示。
示例 1:
输入:
MyNumbers 表:
+-----+
| num |
+-----+
| 8 |
| 8 |
| 3 |
| 3 |
| 1 |
| 4 |
| 5 |
| 6 |
+-----+
输出:
+-----+
| num |
+-----+
| 6 |
+-----+
解释:单一数字有 1、4、5 和 6 。
6 是最大的单一数字,返回 6 。
示例 2:
输入:
MyNumbers table:
+-----+
| num |
+-----+
| 8 |
| 8 |
| 7 |
| 7 |
| 3 |
| 3 |
| 3 |
+-----+
输出:
+------+
| num |
+------+
| null |
+------+
解释:输入的表中不存在单一数字,所以返回 null 。
2.题目思路和难点
2.1思路
改题目要想找到存在最大的单一数字思路并不难。
思路:先通过num分组,而后通过集聚函数count(num)=1的HAVING过滤条件过滤处重复出现的数字的分组,接着在通过按num数字逆序排序,使用limit获取第一个数据即可。代码如下
#代码2.1
SELECT num
from MyNumbers
GROUP BY(num)
HAVING count(num) = 1
ORDER BY num DESC
LIMIT 0,1
2.2难点解决过程
2.2.1具体难点
- 此时的难点在于如何对于空数据返回为null。(注意空数据是没有返回数据,而返回null值是返回了数据只是结果为null值.
2.2.2解决过程
2.2.2.1错误方案:使用IFNULL函数
遇到此问题的时候,第一反应是寻找百度。百度所提供的解决方案是使用IFNULL()函数或者COALESCE()方法解决。
此时使用IFNULL(expression_1, expression_2 ),此时如果第一个返回的表达式值为null,则返回第二个值。此时百度上面所给的解决方案式在第一个表达式的位置填写要找的字段,然后再第二个表达式填写null,即可实现空数据转化为null。对应代码如下。
# 代码2.1
SELECT IFNULL(num, null) AS num
FROM MyNumbers
GROUP BY(num)
HAVING COUNT(num) = 1
ORDER BY num
LIMIT 0,1;
运行结果
2.2.2.2正确方案:使用聚集函数
此时参看了一位大佬写的题解,感觉帮助巨大,不光提供了解决方案,同时也提供了总结,甚至还进行了扩展,通过IFNULL()函数也可以将空数据转换为null(虽然起作用不是ifnull)。引用链接
解决方案就是通过聚集函数再一次查询返回为空数据的暂存表,此时返回的结果就是null。此时能将空数据查询返回null数据的积聚函数只有以下四个聚集函数(MAX(),MIN(),SUM(),AVG()).此时该题使用MAX聚集函数刚好可以解决该问题。代码如下
SELECT MAX(num) AS num FROM
(SELECT num
FROM MyNumbers
GROUP BY(num)
HAVING COUNT(num)=1
ORDER BYnum DESC
LIMIT 0,1
) AS TEMP;
此处记录以下他总结的表格。
此图片最让人困惑的就是SELECT列,我在此解释以下,此时意思是如果空数据是在from后面,空在from语句,此时返回的数据仍然是空值,但是如果此时的空是在select语句中——即在字段的位置,此时空表格返回的数据为null值。正如以下代码也能正确通过
select ifnull((select max(num)
from my_numbers
group by num
having count(*) = 1
Order by num DESC
limit 1), null) num
此时代码其中用的并非是ifnull,删掉ifnull仍然可以返回努力了,因为()内部的查询为空数据时候ifnull函数并不满足,此时空数据并不等于null,所以它能够成功输出结果实际上是遵循上述的规律。即空数据在select语句中,查询是会将其转化为null。
此时第一种情况空在from语句中返回的结果仍然是没有任何输出。参见如下代码案例。
SELECT IFNULL(t1.num,NULL) num
FROM(
SELECT num
FROM MyNumbers
GROUP BY num
HAVING COUNT(num)=1
ORDER BY num DESC
LIMIT 0,1
) t1;
结果和第一种错误案例一摸一样。