MYSQL: Limiting rows per whereIn()

我与影子孤独终老i 提交于 2019-12-08 12:48:36

问题


users Table

id


user_comments Table

id | user_id | content | created_at


I have a list of user IDs, and I want to grab the latest 3 comments for each user id.

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

This will grab the last 3 comments from all matching IDs, I want the last 3 comments for each ID. 1 query without unions preferred.

I have tried right joining the table on itself but I cant seem to get it right.

** Edit: I cannot rely on the id column for ordering, it must use the date column.

Thanks.


** My Final Solution

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

The answer proposed by @PaulSpiegel did work for me (with caveat), however I ended up going with the above join solution that I made using info from this thread: link

mentioned by Bill Karwin.

Thanks everyone!


回答1:


If you can use id instead of created_at, you can compare the id with the 3rd highest id per user. Which you can find in a subquery with LIMIT 1 OFFSET 2. For the case that a user has less than 3 comments use COALESCE (or IFNULL) to select all comments with id >= 0.

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

If you can not use id for ordering..

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

Note that you then might (though unlikely) get more than 3 comments, if the 3rd and the 4th comment have the same timestamp.




回答2:


Try

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

Inner query uses SQL @ variables that change the value from row to row. Comments of a particular user will be grouped together because of order by user_id. @currentRank variable will be storing row rank in a particular group. @currentRank will be zeroed out when new group starts.

The result is quit optimal as it needs RDMS to iterate over each record of user_comments table only once. However the outer where clause will be executed afterwards.



来源:https://stackoverflow.com/questions/42124031/mysql-limiting-rows-per-wherein

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!