SQL:选择最新帖子和最新帖子,按论坛分组,按最新帖子排序

时间:2013-06-20 19:30:31

标签: mysql sql select group-by sql-order-by

我正在尝试获取

  • 最新主题(ID,主题,时间戳,author_id)和
  • 最新帖子(id,thread_id,timestamp,author_id)
  • 每个论坛(id,name)
  • 按最新帖子排序,独立于主题的创建日期。

为什么吗

我希望能够显示以下详细信息:

"The latest Answer of forum $forum_id was given on Question $thread_id. Here it is: $post_id"

SELECT  f.id AS forum_id,
        f.name AS forum_name,
        t.id AS thread_id,
        t.topic AS thread_topic,
        t.ts AS thread_timestamp,
        p.id AS post_id,
        p.content AS post_content,
        p.ts AS post_timestamp

 FROM   forums f,
        threads t,
        posts p

WHERE   f.id = t.forum_id 
  AND   t.id = p.thread_id

GROUP BY f.id
ORDER BY p.ts

任何建议,如何更改SQL以尽可能多地获得想要的结果?我试图避免使用子查询,但我心胸开阔!

提前致谢!

2 个答案:

答案 0 :(得分:3)

由于MySQL不支持窗口功能,所以我认为没有子查询就可以做任何事情:

SELECT  f.id AS forum_id,
    f.name AS forum_name,
    t.id AS thread_id,
    t.topic AS thread_topic,
    t.ts AS thread_timestamp,
    p.id AS post_id,
    p.content AS post_content,
    p.ts AS post_timestamp

FROM   forums f
JOIN (SELECT t2.forum_id, max(p2.ts) as ts
      FROM posts p2
      JOIN threads t2 ON p2.thread_id = t2.id
      GROUP BY t2.forum_id) max_p ON f.id = max_p.forum_id
JOIN   posts p ON max_p.ts = p.ts
JOIN   threads t ON f.id = t.forum_id AND p.thread_id = t.id
ORDER BY p.ts

当然,缓存最新的结果可以让你这样做而不会调用MAX()的性能损失,但是如果使用正确的索引,这不应该是一个很大的问题......

<强>更新

包含没有帖子和没有线程的论坛的线程的最简洁方法是使用LEFT JOIN而不是INNER JOIN:

SELECT  f.id AS forum_id,
    f.name AS forum_name,
    t.id AS thread_id,
    t.topic AS thread_topic,
    t.ts AS thread_timestamp,
    p.id AS post_id,
    p.content AS post_content,
    p.ts AS post_timestamp

FROM   forums f
LEFT JOIN (SELECT t2.forum_id, max(COALESCE(p2.ts, t2.ts)) as ts, COUNT(p2.ts) as post_count
      FROM threads t2 
      LEFT JOIN posts p2 ON p2.thread_id = t2.id
      GROUP BY t2.forum_id) max_p ON f.id = max_p.forum_id
LEFT JOIN   posts p ON max_p.ts = p.ts
LEFT JOIN   threads t ON f.id = t.forum_id AND (max_p.post_count = 0 OR p.thread_id = t.id)
ORDER BY p.ts

答案 1 :(得分:1)

我可以想到两种“正确”的做法。第一种是使用连接和子查询:

SELECT  f.id AS forum_id,
        f.name AS forum_name,
        t.id AS thread_id,
        t.topic AS thread_topic,
        t.ts AS thread_timestamp,
        p.id AS post_id,
        p.content AS post_content,
        p.ts AS post_timestamp
 FROM   forums f join
        threads t
        on f.id = t.forum_id join
        posts p
        on t.id = p.thread_id
WHERE   t.ts = (select ts from threads t2 where t2.forum_id = t.forum_id order by ts desc limit 1) and
        p.ts = (select ts from posts p2 where p2.thread_id = p.thread_id order by ts desc limit 1)
GROUP BY f.id
ORDER BY max(p.ts)

这种方法的问题在于它返回该线程上最新的线程和最新的帖子。解决这个问题很麻烦(这可能就是你真正想要的。)

子查询获取threadsposts的最新日期。性能取决于您拥有的索引。这可能是可以接受的。这是标准的SQL。

另一个是substring_index() / group_concat()的技巧,特定于MySQL:

SELECT  f.id AS forum_id,
        f.name AS forum_name,
        substring_index(group_concat(t.id order by t.ts desc separator '|'), '|', 1) AS thread_id,
        substring_index(group_concat(t.topic order by t.ts desc separator '|'), '|', 1)  AS thread_topic,
        substring_index(group_concat(t.ts order by p.ts desc separator '|'), '|', 1)  AS thread_timestamp,
        substring_index(group_concat(p.id order by p.ts desc separator '|'), '|', 1)  AS post_id,
        substring_index(group_concat(p.content order by p.ts desc separator '|'), '|', 1)  AS post_content,
        substring_index(group_concat(p.ts order by p.ts desc separator '|'), '|', 1)  AS post_timestamp
 FROM   forums f join
        threads t
        on f.id = t.forum_id join
        posts p
        on t.id = p.thread_id
GROUP BY f.id
ORDER BY max(p.ts);

此版本可能表现更好(因为您已经承担了group by的开销)。必须选择分隔符,因此它不在任何值中。否则,只会显示分隔符前面的部分。

一个优点是线程和帖子是独立处理的,因此您可以获得最新的帖子,另外还有最新的帖子。您可以通过更改order by中的group_concat()条件来获取给定主题上的最新帖子。

另外,要获得所需的订单,您需要按max(p.ts)订购,而不仅仅是p.ts。后者将在论坛上以任意时间戳排序;不能保证它会是最新的。