如何用SQL获取所有用户的最后一次搜索记录?技术求助
解决思路:获取每个用户的最后一次搜索记录
这是个很常见的「分组取最新记录」问题,你之前的思路踩了SQL GROUP BY的典型坑——直接GROUP BY uid后,非聚合字段的返回值是不确定的(不同数据库处理逻辑可能不同,但都不会自动帮你取最新的那条),所以拿不到正确的最后一条搜索记录。下面给你几种靠谱的解决思路,适配不同的数据库版本:
方法1:用窗口函数(推荐,适用于MySQL 8.0+/PostgreSQL/SQL Server等现代数据库)
窗口函数是处理这类分组排序问题最简洁的方式,用ROW_NUMBER()给每个用户的搜索记录按日期降序编号,然后取编号为1的那条就是最新记录:
SELECT uid, itemDescription, date FROM ( SELECT uid, itemDescription, date, ROW_NUMBER() OVER (PARTITION BY uid ORDER BY date DESC) AS rn FROM SEARCH WHERE date BETWEEN '2020-03-01' AND '2020-03-30' ) AS sub WHERE rn = 1;
- 解释:
PARTITION BY uid会把数据按用户分组,ORDER BY date DESC让每组内的记录从最新到最旧排序,ROW_NUMBER()给每组的记录标上1、2、3...,最后筛选rn=1就得到每个用户的最新搜索。 - 如果同一个用户在同一时间有多条搜索记录,
ROW_NUMBER()会随机给它们标不同的号;如果想保留所有同时间的最新记录,可以换成RANK()或者DENSE_RANK()。
方法2:子查询+关联(兼容老版本MySQL 5.x等不支持窗口函数的数据库)
先找出每个用户在指定日期范围内的最大搜索日期,再通过这个日期关联原表,拿到对应的搜索内容:
SELECT s.uid, s.itemDescription, s.date FROM SEARCH s INNER JOIN ( SELECT uid, MAX(date) AS max_date FROM SEARCH WHERE date BETWEEN '2020-03-01' AND '2020-03-30' GROUP BY uid ) AS sub ON s.uid = sub.uid AND s.date = sub.max_date WHERE s.date BETWEEN '2020-03-01' AND '2020-03-30';
- 解释:子查询先得到每个用户的最新搜索日期,然后和原表通过
uid和date关联,就能找到对应用户最新日期的那条记录。 - 注意:如果同一个用户在同一时间有多个搜索记录,这个查询会返回多条;如果只想保留一条,可以加
DISTINCT s.uid, s.itemDescription, s.date或者结合其他条件去重。
方法3:用NOT EXISTS(逻辑直观,兼容大部分数据库)
思路是:找到所有「不存在同用户、且日期比它更晚的搜索记录」的条目,这样的条目就是该用户的最新记录:
SELECT uid, itemDescription, date FROM SEARCH s1 WHERE date BETWEEN '2020-03-01' AND '2020-03-30' AND NOT EXISTS ( SELECT 1 FROM SEARCH s2 WHERE s2.uid = s1.uid AND s2.date BETWEEN '2020-03-01' AND '2020-03-30' AND s2.date > s1.date );
- 解释:对于每条记录
s1,如果找不到同用户s2的记录日期比它晚,那s1就是该用户的最新搜索。 - 同样,如果同一用户同一时间有多条记录,这个查询会返回所有这些记录。
为什么你之前的方法不行?
- 移除
uid条件后只返回一条:因为没有分组,ORDER BY date DESC LIMIT 1只会返回整个表中最新的一条记录,而不是每个用户的。 - 加
GROUP BY uid但结果不对:GROUP BY要求SELECT中的非聚合字段必须出现在GROUP BY里,或者用聚合函数包裹。如果直接写SELECT uid, itemDescription, date GROUP BY uid,数据库会返回每组中随机的一条记录(不是按日期排序后的最新那条),所以结果不符合预期。
内容的提问来源于stack exchange,提问作者letsCode
相关产品推荐
相关产品推荐

