MYSQL:限制每个 whereIn() 的行数
MYSQL: Limiting rows per whereIn()
用户Table
id
user_comments Table
编号 | user_id |内容 | created_at
我有一个用户 ID 列表,我想为每个用户 ID 抓取最新的 3 条评论。
SELECT * FROM user_comments WHERE user_id IN (1, 2, 3, 4, 5)
ORDER BY created_at DESC
LIMIT 3;
这将从 all 个匹配 ID 中获取最后 3 个评论,我想要 each 个 ID 的最后 3 个评论。首选 1 个没有联合的查询。
我已经尝试正确加入 table 本身,但我似乎无法正确加入。
** 编辑:我不能依赖 id 列进行排序,它必须使用日期列。
谢谢。
** 我的最终解决方案
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
Bill Karwin 提到。
谢谢大家!
如果可以使用 id
而不是 created_at
,则可以将 id
与每个用户的第三高 id
进行比较。您可以在带有 LIMIT 1 OFFSET 2
的子查询中找到它。对于用户的评论少于 3 条的情况,使用 COALESCE(或 IFNULL)来 select 所有带有 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
如果不能使用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 条评论。
尝试
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 @变量 逐行更改值。由于 order by user_id
,特定用户的评论将被分组在一起。 @currentRank
变量将存储特定组中的行排名。 @currentRank
新组开始时会清零
结果是最优的,因为它只需要 RDMS 遍历 user_comments
table 的每条记录一次。然而,外层的 where
子句将在之后执行。
用户Table
id
user_comments Table
编号 | user_id |内容 | created_at
我有一个用户 ID 列表,我想为每个用户 ID 抓取最新的 3 条评论。
SELECT * FROM user_comments WHERE user_id IN (1, 2, 3, 4, 5)
ORDER BY created_at DESC
LIMIT 3;
这将从 all 个匹配 ID 中获取最后 3 个评论,我想要 each 个 ID 的最后 3 个评论。首选 1 个没有联合的查询。
我已经尝试正确加入 table 本身,但我似乎无法正确加入。
** 编辑:我不能依赖 id 列进行排序,它必须使用日期列。
谢谢。
** 我的最终解决方案
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
Bill Karwin 提到。
谢谢大家!
如果可以使用 id
而不是 created_at
,则可以将 id
与每个用户的第三高 id
进行比较。您可以在带有 LIMIT 1 OFFSET 2
的子查询中找到它。对于用户的评论少于 3 条的情况,使用 COALESCE(或 IFNULL)来 select 所有带有 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
如果不能使用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 条评论。
尝试
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 @变量 逐行更改值。由于 order by user_id
,特定用户的评论将被分组在一起。 @currentRank
变量将存储特定组中的行排名。 @currentRank
新组开始时会清零
结果是最优的,因为它只需要 RDMS 遍历 user_comments
table 的每条记录一次。然而,外层的 where
子句将在之后执行。