我正在尝试编写一个论坛网站,我想显示一个主题列表。每个帖子都应附有关于第一个帖子(线程的“头部”)以及最后一个帖子的信息。我目前的数据库结构如下:
threads table:
id - int, PK, not NULL, auto-increment
name - varchar(255)
posts table:
id - int, PK, not NULL, auto-increment
thread_id - FK for threads
表中还包含其他字段,但它们与查询无关。我感兴趣的是查询threads
并以某种方式JOIN
使用posts
,以便在单个查询中获得每个线程的第一个和最后一个帖子(没有子查询)。到目前为止,我能够使用多个查询来完成它,并且我已将第一篇文章定义为:
SELECT *
FROM threads t
LEFT JOIN posts p ON t.id = p.thread_id
ORDER BY p.id
LIMIT 0, 1
除了ORDER BY id DESC
之外,最后一篇文章几乎相同。现在,我可以通过以下方式选择多个线程及其第一个或帖子:
SELECT *
FROM threads t
LEFT JOIN posts p ON t.id = p.thread_id
ORDER BY p.id
GROUP BY t.id
但当然我无法同时获得两者,因为我需要同时对ASC
和DESC
进行排序。
这里有什么解决方案?甚至可以使用单个查询吗?有什么方法可以改变我的表的结构来促进这个吗?如果这不可行,那么在这种特殊情况下,您可以提供哪些提示来改善查询性能?
答案 0 :(得分:1)
您可以使用子查询和连接执行某些操作:
SELECT first.text as first_post_text, last.text as last_post_text
FROM
(SELECT MAX(id) as max_id, MIN(id) as min_id FROM posts WHERE thread_id = 1234) as sub
JOIN posts first ON (sub.max_id = first.id)
JOIN posts last ON (sub.min_id = last.id)
但这并不能解决没有子查询的问题。
您可以在threads表中添加列,以便保留每个线程的第一个和最后一个帖子的id。第一篇文章永远不会改变,但每次你添加一篇新帖子时你都必须在线程表中更新该记录,这样你的写入就会翻倍,你可能需要使用一个事务来避免竞争条件。
或者你可以复制有关线程行中第一篇和最后一篇文章的信息。假设您需要海报的user_id,发布的时间戳以及帖子的前100个字符。您可以在线程表中创建6个新列,以包含第一个和最后一个帖子的那些数据。它复制数据,但这意味着您可以显示线程列表而无需查询posts表。