在正常的业务需求中常见的就是IP去重,倒序展示用户最新的10条数据。
例如:
user_login_info 表中有 id(主键、自增),ip,user_id 等字段。
此时需要通过通过IP去重,然后id倒叙。
想到用distinct 来实现去重:
select distinct ip from user_login_info where user_id = 1 order by id desc limit 10;
此时报错提示 排序的id字段不在查询列表中,无法进行排序。
如果放到查询语句中,则去重将无效。
之后又想到用子查询的方式:
select distinct ip from(
select ip,id from user_login_info where user_id = 1 order by id desc;
) tab limit 10
此方式是可以实现去重,但是倒序无效了。
之后考虑不使用 distinct 而选择使用的 Group By。
SELECT ip FROM user_login_info
where user_id = 1
GROUP BY ip
ORDER BY MIN(id) desc limit 10;
ORDER BY MIN(id) 表示按照每组中id的最小值进行排序,也就是通过取每组最小的id值对应的记录顺序来对去重后的 IP 进行排序,当然你也可以使用MAX(id)等其他聚合函数来决定排序依据,不过一般来说按照最小id排序能保证相对原始顺序更靠前的记录优先展示。同样,如果希望降序排序,可写成ORDER BY MIN(id) DESC。
但是实现起来还是有问题。
最后选择使用 ROW_NUMBER() 函数给每行记录添加行号:
SELECT sign, location
FROM (
SELECT sign, location,
ROW_NUMBER() OVER (PARTITION BY sign ORDER BY check_time DESC) AS row_num
-- 按照sign分区,在每个分区内(即针对sign)按验证时间倒序排序,并赋予行号
FROM game_account_check_record
WHERE sign = '***' -- 按照唯一标识
) AS subquery
WHERE row_num <= 2
-- 只取行号小于等于2的记录,也就是该指定用户最新的2条验证记录
ORDER BY row_num;