1

假设我有 2 个表:blog_posts 和类别。每篇博文只属于一个类别,所以这里的两个表之间基本上有一个外键。

我想从每个类别中检索 2 个最后的帖子,是否可以在一个请求中实现这一点?GROUP BY 将对所有内容进行分组,并在每个类别中只留下一行。但我想要其中的 2 个。

执行 1 + N 查询(​​N = 类别数)很容易。首先检索类别。然后从每个类别中检索 2 个帖子。

我相信执行 M 个查询也很容易(M = 我想从每个类别中获得的帖子数)。第一个查询选择每个类别的第一个帖子(带有分组依据)。第二个查询检索每个类别的第二个帖子。等等

我只是想知道是否有人对此有更好的解决方案。我真的不介意为此进行 1+N 查询,但出于好奇心和一般 SQL 知识,将不胜感激!

在此先感谢谁能帮助我。

4

2 回答 2

3
SELECT  p.*
FROM    (
        SELECT  id,
                COALESCE(
                (
                SELECT  datetime
                FROM    posts pi
                WHERE   pi.category = c.id
                ORDER BY
                        pi.category DESC, pi.datetime DESC, pi.id DESC
                LIMIT 1, 1
                ), '1900-01-01') AS post_datetime,
                COALESCE(
                (
                SELECT  id
                FROM    posts pi
                WHERE   pi.category = c.id
                ORDER BY
                        pi.category DESC, pi.datetime DESC, pi.id DESC
                LIMIT 1, 1
                ), 0) AS post_id
        FROM    category c
        ) q
JOIN    posts p
ON      p.category <= q.id
        AND p.category >= q.id
        AND p.datetime >= q.post_datetime
        AND (p.datetime, p.id) >= (q.post_datetime, q.post_id)

对此进行索引posts (category, datetime, id)以使其快速。

注意p.category <= c.id AND p.category >= c.idhack:这使得MySQL使用Range checked for each record哪个索引效率更高。

有关类似问题,请参阅我博客中的这篇文章:

于 2009-12-15T13:46:55.867 回答
3

查看这篇MySQL 文章,了解如何在任意复杂的分组中处理前 N 个事物;这是好东西。你可以试试这个:

SET @counter = 0;
SET @category = '';

SELECT
  *
FROM
(
  SELECT
    @counter := IF(posts.category = @category, @counter + 1, 0) AS counter,
    @category := posts.category,
    posts.*
    FROM
      (
      SELECT
        *
        FROM test
        ORDER BY category, date DESC
      ) posts
) posts
HAVING counter < 2
于 2009-12-15T13:47:56.267 回答