如何不使用子查询,按UserID去重后限制SQL查询行数?
实现按前N个不同用户ID获取所有关联记录
针对你的需求,要高效获取前2个不同用户ID对应的所有猫咪记录,使用窗口函数是最优方案,以下是正确的写法及说明:
错误分析
你原SQL的JOIN条件存在错误:ON U.id = C.id 应该改为 ON U.id = C.userID,否则会错误关联用户ID和猫咪ID,而非用户ID和猫咪所属用户ID。另外直接加LIMIT 2只会返回前2条记录,无法按用户ID分组限制。
正确的窗口函数实现
使用DENSE_RANK()窗口函数为每个用户ID分配排名,再筛选排名≤2的记录,这样能保证获取前2个用户的所有关联猫咪数据,且性能优于子查询IN的方式(尤其适合大表,可利用user.id和cats.userID的索引):
SELECT U.id AS user_id, C.name AS cat_name FROM user U INNER JOIN ( -- 为每个猫咪所属的用户ID按顺序排名 SELECT name, userID, DENSE_RANK() OVER (ORDER BY userID) AS user_rank FROM cats ) C ON U.id = C.userID WHERE C.user_rank <= 2;
逻辑说明
- 子查询中,
DENSE_RANK() OVER (ORDER BY userID)会按照userID的升序为每个用户分配唯一排名,同一个用户的所有猫咪记录会获得相同的排名。 - 外层关联用户表后,筛选排名≤2的记录,即可得到前2个用户的所有猫咪数据。
自定义排序规则
如果需要按用户的其他字段(比如年龄)来选择前2个用户,只需修改窗口函数的排序条件即可,例如按用户年龄升序选前2个:
SELECT U.id AS user_id, C.name AS cat_name FROM ( SELECT U.id, C.name, DENSE_RANK() OVER (ORDER BY U.age) AS user_rank FROM user U INNER JOIN cats C ON U.id = C.userID ) ranked_data WHERE ranked_data.user_rank <= 2;
执行结果
以你的表数据为例,执行第一个SQL会得到以下结果:
| user_id | cat_name |
|---|---|
| 1 | miez |
| 1 | caty |
| 2 | random |
这正是你需要的前2个不同用户ID对应的所有记录。
内容的提问来源于stack exchange,提问作者user16405471
相关产品推荐
相关产品推荐

