没有子查询的最新数据分组

Posted

技术标签:

【中文标题】没有子查询的最新数据分组【英文标题】:Latest data group-by without a subquery 【发布时间】:2016-06-06 10:25:15 【问题描述】:

这是一个很常见的情况,但我不确定我是否做错了什么。

TABLE POSTS [ ID, USER_ID, TOPIC_ID, TIME ]

我只想获取每个用户在 topic_id '1' 上的最后一篇文章

SELECT p.*
FROM
  posts p,
  (
    SELECT   user_id, max(time) mtime
    FROM     posts
    WHERE    topic_id = 1
    GROUP BY user_id
  ) pm
WHERE
  p.user_id = pm.user_id AND
  p.time    = pm.mtime

这是正确的吗?没有子查询有没有办法做到这一点?

是否可以选择通过 spring-data 查询获取这些数据,或者这只是 JDBC/存储过程?

【问题讨论】:

这是正确的 - 但始终使用显式 JOIN 语法 啊,我说得太早了。您需要在子查询的 SELECT 中包含 user_id,最佳实践要求您应该在 GROUP BY 中包含 topic_id(尽管在这种情况下并非绝对必要) 是的,我有点搞砸了从我的域到“帖子”的翻译,它应该是“SELECT user_id, max(time)”而不是“topic_id” - 已编辑 【参考方案1】:

您可以在不使用子查询的情况下通过 join 获取每个用户的最新帖子:

SELECT p.* 
FROM posts p
LEFT OUTER JOIN posts t
ON(p.user_id = t.user_id and p.time < t.time and t.topic_id = 1)
WHERE p.topic_id = 1 and t.topic_id is null

【讨论】:

这很有趣,我还没有看到这个“技巧”。但是,它会获得所有用户关于任何主题的最后一篇文章,而不是主题“1” - 有没有办法过滤结果? @qzshard 是的,当然,在 ON 子句中,更新了答案.. 如果它对你有帮助,我将不胜感激(^)和批准(V) 这不能像给定的那样工作,每个 p.* 行 topic_id 1 将被返回(因为 t.topic_id 将为 NULL)包括 and p.topic_id = 1 t where 子句会有所帮助 你的子查询?肯定是这个 @qzshard - 这将取决于索引(很容易更改)和数据。如果您有相当少量的用户和大量主题,则子查询将返回少量行,因此该连接上缺少索引将无关紧要。但是这里的 LEFT OUTER JOIN 会返回大量行,然后在 WHERE 子句中排除大部分行,这会减慢速度。但如果有大量用户,而每个用户的主题数量很少,则情况正好相反。【参考方案2】:

另一个避免子查询的解决方案(但同样可能没那么快)是使用 substring_index 按时间降序为您想要最新的每个字段排序,然后使用 SUBSTRING_INDEX 来获取 SUBSTRING_INDEX 返回的第一个条目。

SELECT user_id, 
    SUBSTRING_INDEX(GROUP_CONCAT(`id` ORDER BY `time` DESC), ',', 1),
    SUBSTRING_INDEX(GROUP_CONCAT(`topic_id` ORDER BY `time` DESC), ',', 1),
    SUBSTRING_INDEX(GROUP_CONCAT(`time` ORDER BY `time` DESC), ',', 1)
FROM posts
WHERE    topic_id = 1
GROUP BY user_id

【讨论】:

【参考方案3】:

我不确定如何在这里避免sub-query,但另一种方法是

SELECT p.*
FROM   posts p
WHERE  p.time = (SELECT Max(time) mtime
                 FROM   posts pm
                 WHERE  pm.topic_id = 1
                        AND p.user_id = pm.user_id) 

窗口函数Row_number 在这种情况下会很有帮助,不幸的是mysql 不支持

【讨论】:

谢谢,这是我在其他问题中看到的另一种方式。但就性能而言,这不是一个非常激烈的查询(与原来相比)吗? @qzshard- 你可以用你的实时数据进行测试【参考方案4】:

要在没有子查询的情况下执行此操作,请使用 HAVING

SELECT   user_id, topic_id,  time
FROM     posts
WHERE    topic_id = 1
GROUP BY user_id
HAVING time = max(time)

【讨论】:

HAVING time =.. Mysql 是否允许这样做 没试过,但我想是这样的:dev.mysql.com/doc/refman/5.0/en/group-by-handling.html 不起作用,你不能在单行上下文中使用“有”

以上是关于没有子查询的最新数据分组的主要内容,如果未能解决你的问题,请参考以下文章

mysql 分组子查询sql怎么写

查找没有子查询的最大 sID [重复]

MySQL 未在子查询中使用 INDEX

子查询分组后主查询怎么接收count

sql子查询可以再分组吗

Mysql从入门到入魔——5. 聚集分组子查询