2012-11-19 40 views
13

表:PHP的MySQL集团通过获得最新的记录,而不是第一个记录

(`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 

问题:

如何重写查询,以便我t返回post_id - > 83而不是post_id - > 81?

它们都具有相同的论坛和主题ID,但POST_ID - > 81比POST_ID的旧日期 - > 83.

但似乎集团通过获得的“第一”的记录,而不是“最新'一个。

我试图改变查询

SELECT post_id, forum_id, topic_id, MAX(post_time) 

但同时返回POST_ID 81和83

回答

24

如果您选择了未在组合子句中使用且不是聚合的属性,则结果未指定。 I.e您不知道哪些行选择了其他属性。 (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; 
+0

感谢您的解释和代码。两个查询都有效。 – shanebp

+0

我用过你第​​一个查询,但它在我改变 ...之前没有工作... WHERE post_time = ... TO ... WHERE post_time IN ...因为我得到了更多的结果。 –

+0

这是为什么这么麻烦?使用SQL它将只是'选择*从[表] GROUP BY [列]'选择最新的,而不是最古老的,似乎合乎逻辑的权利? –

10

这不是很漂亮,但它的工作原理:

SELECT * FROM (SELECT post_id, forum_id, topic_id FROM posts 
ORDER BY post_time DESC) as temp 
GROUP BY topic_id 
+0

这消除重复,但结果是主题ID ASC – shanebp

+2

添加这对您的查询的顺序进行它的工作:ORDER BY post_time DESC LIMIT 5 – shanebp

5

尝试类似

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 bylimit

+0

结果是一个空数组。 – shanebp

+0

我稍微编辑了查询。我不明白为什么它不起作用。我没有尝试过,但这是一种常用技术。嵌套查询是。假设内部查询返回正确的结果,那么外部查询应该给出结果。 – NappingRabbit

+0

如果你想调试,首先运行内部查询。 – NappingRabbit

0

也许不是这样做的最佳方式,但有时功能GROUP_CONCAT()可以userfull,它将返回排序像你想对所有的字符串值并用逗号分隔(耦合值由空格分隔)。然后我使用函数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

0

这也将正常工作适合你。

SELECT * 
FROM (
    SELECT post_id, forum_id, topic_id FROM posts 
    ORDER BY post_time DESC 
    LIMIT 5 
) customeTable 
GROUP BY topic_id 
相关问题