问题
如何把数据按照某一个字段排重保留我们要的哪行记录,然后以我们想要的顺序排序好以后,查询出来?
今天花了一整天的时间搞这个问题,本来以为是很简单的问题就小瞧它了,结果发现网上一大堆错误答案,我也是醉了。。
文章略长,主要讲述的是我的探索(踩坑)过程,想要直接看解决方法的请拉到最后,拿走不谢~
过程
先说一下问题所在,比如说,现在有一个表,体温测量。结构如下:
假设我们每隔一段时间去给用户测量一次体温,那么同一个用户就会产生多条记录。现在我们想要查询出每一个用户最新一条测量数据,怎么查?
接下来我说说我的踩坑历程:
是不是觉得很简单,先分组,把重复的数据排掉:
select * from tplay_temperature_record group by user_id;
查询结果:
我去,不对啊,我想要的是最新的一条,id为51的那条数据才是我想要的啊,怎么给我返回了id为50的?不行,看来我得先排好序,再进行排重,(这个时候我以为group by拿的是第一条):
第一步,先排序:
select * from tplay_temperature_record order by create_time desc;
看到结果,已经排好序了。
然后我们用到子查询去进行分组:
select * from (select * from tplay_temperature_record order by create_time) as a group by a.user_id;
结果:
我去,不对啊,id为51的那条,咋又给我整没了。
然后我开始在网上各种搜,在这个地址:https://blog.csdn.net/weixin_38450840/article/details/88836170
发现有人这样说:
卧槽,这样子的吗?原谅我年少无知,才疏学浅,那么我们试试,加上limit:
select * from (select * from tplay_temperature_record order by create_time limit 100) as a group by a.user_id;
结果:
还是一样,没有任何改变,我不知道是不是mysql版本太低的原因,我用的是5.5.62,反正就是没效果。
再看看其他大神的思路吧
于是我找到了这篇文章:https://blog.csdn.net/u012660464/article/details/78605078/
这篇文章的核心思想是:先分组,再排序。
对啊,我们想的是先排序再分组,如果反过来呢?
文章里说到:
按照他说的,写一个:
SELECT * FROM (select * from tplay_temperature_record order by user_id, create_time DESC) b GROUP BY b.user_id;
结果:
啥情况,还是不对?接着往下翻,看到底下评论一堆叫苦连天的。。
好吧,看来广大网友和我一样,没从这篇文章中获得什么~
解决
喜闻乐见的环节来了,在无数次的挣扎之后,终于获得了正确的方法,也是参考了下面这篇文章,感谢大神!
地址:https://www.cnblogs.com/afei-happy/p/3783520.html
核心思想,两个表的思想,就是先分组作为另一个表,然后进行子查询,用user_id去关联,对结果进行排序。
上步骤:
第一步,分组,排除重复,保留想要的哪一行记录。这里我们是按照user_id排重,查询时间最近的那条,就可以这样写:
SELECT user_id, max(create_time) max_day, temperature FROM tplay_temperature_record GROUP BY user_id
第二步,子查询,把上述的查询结果当成另一个表B,然后原表当成表A,用user_id去关联,然后对查询到的结果进行排序。
SELECT A.* FROM tplay_temperature_record A, ( SELECT user_id, max(create_time) max_day, temperature FROM tplay_temperature_record GROUP BY user_id ) B WHERE A.user_id = B.user_id AND A.create_time = B.max_day ORDER BY A.create_time DESC
结果:
完美!
总结一下,这一类问题,看似简单,其实复杂。
我自己感觉这个问题有两个难点:
1、group by分组后如何保留自己想要的那一行数据?搭配聚合方法,或许有奇效
2、分组后的数据如何排序?其实不太好排序,为何不变通一下,分成两个表,然后关联一下查询再排序呢?
除了这种方法,肯定有其他的,如果有其他方法的,希望在评论区大家一起讨论下。
---------------------------------------------------------------------------------------------------------------------------------------
不好意思,找到一个更简单的写法:
SELECT *, max(create_time) max_day FROM tplay_temperature_record GROUP BY user_id ORDER BY max_day DESC
都不需要用到“两个表”的思想。