php mysql Group By获取最新记录,而不是第一条记录
Posted
技术标签:
【中文标题】php mysql Group By获取最新记录,而不是第一条记录【英文标题】:php mysql Group By to get latest record, not first record 【发布时间】:2012-11-19 18:04:10 【问题描述】:桌子:
(`post_id`, `forum_id`, `topic_id`, `post_time`)
(79, 8, 4, '2012-11-19 06:58:08');
(80, 3, 3, '2012-11-19 06:58:42'),
(81, 9, 9, '2012-11-19 06:59:04'),
(82, 11, 6, '2012-11-19 16:05:39'),
(83, 9, 9, '2012-11-19 16:07:46'),
(84, 9, 11, '2012-11-19 16:09:33'),
查询:
SELECT post_id, forum_id, topic_id FROM posts
GROUP BY topic_id
ORDER BY post_time DESC
LIMIT 5
结果:
[0] => [post_id] => 84 [forum_id] => 9 [topic_id] => 11
[1] => [post_id] => 82 [forum_id] => 11 [topic_id] => 6
[2] => [post_id] => 81 [forum_id] => 9 [topic_id] => 9
[3] => [post_id] => 80 [forum_id] => 3 [topic_id] => 3
[4] => [post_id] => 79 [forum_id] => 8 [topic_id] => 4
问题:
如何重写查询,使其返回 post_id -> 83 而不是 post_id -> 81 ?
他们都有相同的论坛和主题 ID,但 post_id -> 81 的日期比 post_id -> 83 的日期更早。
但 Group By 似乎获得了“第一条”记录,而不是“最新”记录。
我尝试将查询更改为
SELECT post_id, forum_id, topic_id, MAX(post_time)
但返回 post_id 81 和 83
【问题讨论】:
【参考方案1】:如果您选择未在 group 子句中使用且不是聚合的属性,则结果未指定。 即您不知道其他属性是从哪些行中选择的。 (sql标准不允许这样的查询,但是mysql比较宽松)。
然后应该编写查询,例如作为
SELECT post_id, forum_id, topic_id
FROM posts p
WHERE post_time =
(SELECT max(post_time) FROM posts p2
WHERE p2.topic_id = p.topic_id
AND p2.forum_id = p.forum_id)
GROUP BY forum_id, topic_id, post_id
ORDER BY post_time DESC
LIMIT 5;
或
SELECT post_id, forum_id, topic_id FROM posts
NATURAL JOIN
(SELECT forum_id, topic_id, max(post_time) AS post_time
FROM posts
GROUP BY forum_id, topic_id) p
ORDER BY post_time
LIMIT 5;
【讨论】:
我使用了你的第一个查询,但在我改变之前它不会工作...... WHERE post_time = ... TO ... WHERE post_time IN ... 因为我得到了更多的结果。 为什么这么麻烦?使用 SQL 将只是SELECT * FROM [table] GROUP BY [column]
选择最新的而不是最旧的,看起来合乎逻辑吧?
还有添加计数的方法。【参考方案2】:
它不是很漂亮,但它很有效:
SELECT * FROM (SELECT post_id, forum_id, topic_id FROM posts
ORDER BY post_time DESC) as temp
GROUP BY topic_id
【讨论】:
这会删除重复项,但结果按主题 id asc 的顺序排列 将此添加到您的查询中使其工作:ORDER BY post_time DESC LIMIT 5【参考方案3】:尝试类似的东西
SELECT post_id, forum_id, topic_id
FROM (SELECT post_id, forum_id, topic_id
FROM posts
ORDER BY post_time DESC)
GROUP BY topic_id
ORDER BY topic_id desc
LIMIT 0,5
根据需要更改 order by
和 limit
。
【讨论】:
结果是一个空数组。 我稍微编辑了查询。我不明白为什么它不起作用。我没有尝试过,但这是一种常见的技术。即嵌套查询。假设内部查询返回正确的结果,外部查询应该给出一个结果。 如果要调试,请先运行内部查询。 试过你的编辑,仍然返回一个空数组。内部查询返回单个结果,即最近的帖子。 就性能而言,这似乎比公认的选项更好。我们有一个大表,在条件下使用子查询大约需要 45 秒,而此方法运行时间不到一秒。【参考方案4】:也许不是最好的方法,但有时函数 group_concat() 可以是全用户的,它会返回一个所有聚合值的字符串,这些值按你想要的方式排序并用逗号分隔(耦合值是用空格隔开)。然后我使用函数 SPLIT_STRING() 来剪切字符串中的第一个 id。
SELECT
post_id,
SPLIT_STRING( group_concat( forum_id, post_time ORDER BY post_time DESC ) ,' ',1 )as forum_id,
SPLIT_STRING( group_concat( topic_id, post_time ORDER BY post_time DESC ) ,' ',1 )as topic_id ,
FROM posts
GROUP BY topic_id
ORDER BY post_time DESC
LIMIT 5
所以聚合的 forum_id, post_time 将是这样的:
81 2012-11-19 06:59:04,83 2012-11-19 16:07:46
所以你需要使用整数和日期时间对的字符串表示,每对用逗号分隔,所以我使用这个函数来获取第一个 INT:
CREATE FUNCTION SPLIT_STRING(str VARCHAR(255), delim VARCHAR(12), pos INT)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(str, delim, pos),
LENGTH(SUBSTRING_INDEX(str, delim, pos-1)) + 1),
delim, '');
注意:函数 SPLIT_STRING(str, delim, pos) 在这里找到:Equivalent of explode() to work with strings in MySQL
【讨论】:
【参考方案5】:这也适合你。
SELECT *
FROM (
SELECT post_id, forum_id, topic_id FROM posts
ORDER BY post_time DESC
LIMIT 5
) customeTable
GROUP BY topic_id
【讨论】:
以上是关于php mysql Group By获取最新记录,而不是第一条记录的主要内容,如果未能解决你的问题,请参考以下文章
在 mysql 中使用 group by 查询和 order by 查询选择
获取group by platform和semver的两条最新记录
在 sqlalchemy 中使用 distinct()/group_by() 获取基于每个“名称”列的最新记录
具有最新记录的 Oracle 查询 GROUP BY [重复]