挑战MySQL查询

时间:2011-06-02 05:05:52

标签: mysql

我正在开发一个需要独特查询的博客应用。

问题:我需要显示一个父帖子,所有孩子的帖子(在要求分页之前达到某个数字),以及每个子帖子和父母最多5条评论。

我写了这个查询,但它不起作用,因为它只会返回属于父帖的5条评论。

SELECT
    posts.id, posts.postTypeId, posts.parentId, posts.ownerUserId, posts.body
, users.id AS authorId, users.displayname AS authorDisplayName
, comments.id AS commentId, comments.text AS commentText
, comments.commentOwnerUserId, comments.commentOwnerDisplayName
FROM posts
JOIN users ON posts.owneruserid = users.id
LEFT JOIN ( SELECT comments.id, comments.postId, comments.text, commenters.id AS commentOwnerUserId, commenters.displayname AS commentOwnerDisplayName
        FROM comments
        JOIN users AS commenters ON comments.userid = commenters.id
        ORDER BY comments.createdat ASC
        LIMIT 0,5 ) AS comments ON comments.postid = posts.id
WHERE posts.id = @postId OR posts.parentId = @postId
ORDER BY posts.posttypeid, posts.createdAt

查询返回父帖子,它的所有孩子以及它遇到的前5条评论(通常它们属于父级,因为我们按postTypeId排序,而父级是第一篇帖子)。如果第一篇文章没有5条评论,它将在下一篇文章中移动并返回这些评论,直到达到5条限制。

我需要的是返回一个父帖子及其所有子帖子,以及每个孩子(父母)最多5条评论。我还需要每个帖子和评论的所有者数据。

更新如果可以扩展,我可以使用多个查询执行此操作。唯一的条件是父和子帖子检索发生在同一个查询中。

知道怎么写这样的查询吗?我在下面包含了我的架构。

/* Posts table */
CREATE TABLE `posts` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `posttypeid` int(10) NOT NULL,
  `parentid` int(10) DEFAULT NULL,
  `body` text NOT NULL,
  `userid` int(10) NOT NULL,
  `createdat` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
KEY `parentId` (`parentid`)
KEY `userId` (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=572 DEFAULT CHARSET=utf8

/* Comments table */
CREATE TABLE `comments` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `postid` int(10) NOT NULL,
  `userid` int(10) NOT NULL,
  `text` text NOT NULL,
  `createdat` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `postId` (`postid`),
  KEY `userId` (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

/* users table */
CREATE TABLE `users` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `email` varchar(50) NOT NULL,
  `displayname` varchar(50) NOT NULL,
  `createdat` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8

4 个答案:

答案 0 :(得分:2)

听起来你正在寻找存储分层数据。这不是一个难题,因为它有点耗时。我建议你阅读几年前由Mike Hillyer撰写的一篇名为Managing Hierarchical Data in MySQL的非常好的文章。它有一些非常好的概念建议以及你正在设计的那种系统的示例实现。绝对阅读“查找节点的直接下属”部分。 :)

答案 1 :(得分:2)

我假设你会有某种分页来限制顶级帖子的数量。

您还需要一些关于评论数量,帖子表格中的子信息或帖子摘要表的摘要信息。

评论表需要逐列列出

1:获取所有父帖子,(parentId = 0)&构造postids的IN子句

2:通过传递1中获得的postid来获取所有儿童帖子,按postid排序,这将有助于隔离。将这些帖子添加到整个IN子句中    通过传递来自1&的postids获得评论2。    使用评论数量限制评论数量&序列列    例如:加入评论& post_summary post_comment_seq之间(noofcommentsforthepost - 5)和noofcommentsforthepost

您可以在此处查看条款效果Performance of MYSQL "IN"

答案 2 :(得分:2)

我已经从Your Previous Question调整了另一个查询,只是在您的ParentID上包含一个WHERE子句。那是我不知道你想要限制回报的条件。我添加了帖子ID =你想要的那个或者ParentID =你想要的那个。

通过POST ID获得ORDER,它自然会将起始父ID放在第一个位置,因为其他ID将按顺序从其中派生出来。我想这会再次解决你。

答案 3 :(得分:1)

我认为每个孩子只有一个父母。然后,我认为这将有效:

SELECT p.*             <-- post details
     , u.*             <-- user details
     , cc.*            <-- comment details
FROM 
  ( ( SELECT parentid AS id
      FROM posts
      WHERE posts.id = @mypostid     <-- the id of the post we want 
    )
    UNION ALL
    ( SELECT child.id
      FROM posts AS parent
        JOIN posts AS child
          ON child.parentid = parent.id
      WHERE parent.id = 
            ( SELECT posts.parentid
              FROM posts
              WHERE posts.id = @mypostid)   <-- the id of the post we want 
      ORDER BY child.createdat            <-- any order you prefer
      LIMIT x, 5                          <-- 5 children posts
    )
  ) AS pp
  JOIN posts p
    ON p.id = pp.id
  JOIN users
    ON users.id = p.userid
  JOIN comments cc
    ON cc.postid = pp.id
WHERE cc.postid IN
  ( SELECT c.id
    FROM comments c
    WHERE c.postid = pp.id
    ORDER BY c.createdat             <-- any order you prefer
    LIMIT y, 5                       <-- 5 comments for every post
  )

对于前五个孩子的帖子,x,5应该替换为0,5,对于前五个评论,y,5应该替换为0,5 5,5。然后,10,5代表接下来的五个,This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' 代表接下来的五个,等等。


<强>更新

抱歉,我的错误。上面给出了错误:

{{1}}

我会高兴地解决这个问题:)