【问题标题】:MYSQL: Limiting rows per whereIn()MYSQL:限制每个 whereIn() 的行
【发布时间】:2017-06-26 17:09:26
【问题描述】:

用户表

id


user_cmets 表

标识 |用户 ID |内容 | created_at


我有一个用户 ID 列表,我想为每个用户 ID 获取最新的 3 个 cmets。

SELECT * FROM user_comments WHERE user_id IN (1, 2, 3, 4, 5) 
ORDER BY created_at DESC
LIMIT 3;

这将从 所有 匹配的 ID 中获取最后 3 个 cmets,我想要 每个 ID 的最后 3 个 cmets。首选 1 个不带联合的查询。

我已尝试自行正确加入表格,但似乎无法正确完成。

** 编辑:我不能依赖 id 列进行排序,它必须使用 date 列。

谢谢。


** 我的最终解决方案

SELECT user_comments.* FROM user_comments
LEFT OUTER JOIN user_comments user_comments_2
ON user_comments.post_id = user_comments_2.post_id 
    AND user_comments.id < user_comments_2.id    
where user_comments.post_id in (x,x,x) 
GROUP BY user_comments.id 
HAVING COUNT(*) < 3 
ORDER BY user_id, created_at

@PaulSpiegel 提出的答案确实对我有用(有警告),但是我最终选择了使用来自该线程的信息制作的上述连接解决方​​案:link

比尔·卡尔文提到。

谢谢大家!

【问题讨论】:

  • SELECT * FROM user_cmets WHERE user_id=1 OR user_id=2 OR user_id=3 OR user_id=4 ORDER BY created_at DESC LIMIT 3;
  • 你有 AUTO_INCREMENT 列吗?
  • @PaulSpiegel - 是的,id 列是 auto_inc。
  • @BillKarwin - 我能够使用该线程以正确的日期顺序工作。谢谢!

标签: mysql greatest-n-per-group where-in right-join sql-limit


【解决方案1】:

如果您可以使用id 而不是created_at,您可以将id 与每个用户的第三高id 进行比较。您可以在带有LIMIT 1 OFFSET 2 的子查询中找到它。对于用户少于 3 个 cmets 的情况,使用 COALESCE(或 IFNULL)选择所有带有 id &gt;= 0 的 cmets。

SELECT * 
FROM user_comments c
WHERE user_id IN (1, 2, 3, 4, 5)
  AND id >= COALESCE((
    SELECT id
    FROM user_comments c1
    WHERE c1.user_id = c.user_id
    ORDER BY id DESC
    LIMIT 1
    OFFSET 2
), 0)
ORDER BY user_id, id DESC

如果您不能使用id 订购..

SELECT * 
FROM user_comments c
WHERE user_id IN (1, 2, 3, 4, 5)
  AND created_at >= COALESCE((
    SELECT created_at
    FROM user_comments c1
    WHERE c1.user_id = c.user_id
    ORDER BY created_at DESC
    LIMIT 1
    OFFSET 2
), '1970-01-01 00:00:00')
ORDER BY user_id, created_at DESC

请注意,如果第 3 条和第 4 条评论具有相同的时间戳,那么您可能(尽管不太可能)获得超过 3 个 cmets。

【讨论】:

  • 不幸的是,我不能依赖 id 列来订购 cmets,因为在我的应用程序中它们可以保存为草稿,并在以后发布。
  • @magnito 这也可以使用时间戳 - 但请阅读注释。我还在子查询中添加了缺少的 ORDER BY 子句。
  • 我能够让这个大部分工作,但我最终选择了 BillKarwin 提到的线程中提出的连接解决方​​案。重复日期没有同样的问题,而且速度更快(在我的情况下)。
【解决方案2】:

试试

select * 
from (
    select *, 
        @currentRank := if(@prevId = user_id, @currentRank, 0) + 1 as rank, 
        @prevId := user_id
    from user_comments
    order by user_id, created_at desc) as user_comments 
where rank <= 3

内部查询使用 SQL @ variables 将值逐行更改。由于order by user_id,特定用户的评论将被组合在一起。 @currentRank 变量将存储特定组中的行排名。 @currentRank 将在新组开始时清零。

结果是最优的,因为它只需要 RDMS 对 user_comments 表的每条记录进行一次迭代。然而,外部的where 子句将在之后执行。

【讨论】:

    猜你喜欢
    • 2014-05-31
    • 2013-02-25
    • 2019-09-03
    • 2022-01-16
    • 2019-02-14
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    相关资源
    最近更新 更多