1

我正在建立一个简单的论坛。我需要显示的是一个包含最新主题的列表,并且在每个主题附近它是最新的回复/帖子。就像是:

Topic name:         | Last reply:
Topic name 1 here   | 2013-02-01 by username1
Topic name 2 here   | 2013-01-01 by username2
etc.

问题是主题和回复都在同一个表中,称为“页面”。该表有一个字段模板,其中当然包含表“模板”的 ID。

因此,我只需加入模板并按 Template.name 过滤记录“论坛主题”

这将返回所有主题。因为我还需要每个主题的最新回复,所以我决定在同一模板上使用过滤器进行子查询,但现在记录“论坛回复”并按回复.日期 DESC 排序,并使用 LIMIT 1 返回最新回复这个话题。现在是时候显示我当前的查询,该查询适用于至少包含 1 个回复的主题:

/*----some fields to return----*/
SELECT TopicContent.title, ReplyContent.title, Reply.date, Reply.id, 
(
  /*----subquery to return latest reply id used inside HAVING later on----*/
  SELECT Reply.id
  FROM pages AS Reply
  INNER JOIN templates AS Template ON Reply.template = Template.id
  WHERE Reply.parent_id = Topic.id
  AND Template.name =  'Forum reply'
  ORDER BY Reply.date DESC 
  LIMIT 1
) AS reply_id
FROM pages AS Topic
INNER JOIN templates AS Template ON Topic.template = Template.id
INNER JOIN page_content AS TopicContent ON Topic.id = TopicContent.page
/*----left join used because topic could have zero replies if new----*/
LEFT JOIN pages AS Reply ON Topic.id = Reply.parent_id
LEFT JOIN page_content AS ReplyContent ON Reply.id = ReplyContent.page
WHERE Template.name =  'Forum topic'
HAVING Reply.id = reply_id
/*--------------------------------------------------------------------------------*/
/*----HAVING            | returns not all topics but with correct latest reply----*/
/*----GROUP BY Topic.id | returns topics correctly but incorrect latest reply-----*/

现在最重要的是,如果提交了一个新主题,它还没有包含任何回复。

因此,当我使用 HAVING 时,它仅返回还包含至少一个回复的主题。并且当使用 GROUP BY 时,它不会返回包含一个或多个回复的主题的最新回复。对于不包含回复的主题,它返回 NULL 这很好。

我需要更改 JOINS 吗?解决这个问题的任何想法。非常感谢!

4

2 回答 2

1

我会将 MaxId 子查询移至 from 子句,因为您使用 GROUP BY 的方式不适用于您要执行的操作。在这里,您只需将结果集加入到检索 MaxId 字段的子查询中。

SELECT
*
FROM 
   pages
   .
   .
   .
   LEFT OUTER JOIN 
   (
   SELECT 
      ReplyId As [MaxId], 
      p.Template
   FROM 
      Pages p INNER JOIN Templates t ON p.Template = t.Id
   WHERE
      TemplateName = 'Forum Reply'
   ORDER BY ReplyDate LIMIT 1
   ) a ON a.Template = pages.Template
WHERE 
   Template.name =  'Forum topic'

或者(如果多个第一个回复的时间完全相同,则此回复可能会给您多个回复,在这种情况下您可以限制结果)

SELECT
   *
FROM
   pages
   .
   .
   .
   (SELECT
      ReplyId As [MaxiId],
      Template
   FROM
      Pages p INNER JOIN
      Templates t ON p.Template = t.id LEFT OUTER JOIN
      (SELECT 
         p.Template, 
         MIN(ReplyDate) AS [FirstReplyDate]
      FROM      
         Pages p INNER JOIN
         Templates t ON p.Template = t.id
      WHERE
         TemplateName = 'Forum Reply'
      GROUP BY
         p.Template) b ON b.Template = t.id
   WHERE 
      p.ReplyDate = b.FirstReplyDate
   ) a ON a.Template = pages.Template

无论哪种方式,您都应该将第一个回复子查询移至 From 子句

于 2013-06-02T01:16:53.503 回答
0

这还不是答案,而是向发布者询问更多信息,但由于评论太长,我将在这里发布。

根据您的查询,我可以得出结论,您的表看起来像这样

templates(id, name)
pages(id, parent_id, date, template)
page_contents(page, title)

pages存储post的结构,page_contents存储post的内容,template确定post的类型。我对么?

问题:

  • parent_id 的值是多少,如果是主题,不是回复。由于回复在主题下,所以parent_id应该是主题的ID。但是,topic不属于任何topic,所以基本上应该是0或者NULL,对吗?
  • 您是否仅限于这种数据库设计,从我的角度来看,这种数据库设计不适合论坛,因为要检索如此简单的东西,您必须 INNER JOIN 一堆表。
于 2013-06-02T00:59:06.620 回答