没有子查询的最新数据分组
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
不起作用,你不能在单行上下文中使用“有”以上是关于没有子查询的最新数据分组的主要内容,如果未能解决你的问题,请参考以下文章