我正在与kohana建立一个论坛。我知道那里已经有好的,免费的论坛软件了,但这是一个家庭网站,所以我想我会用它作为学习经验。我也没有使用Kohana内置的ORM,因为我想在构建论坛的过程中更多地了解SQL。
对于我的论坛,我有4个主要表格:
USERS
TOPICS
POSTS
COMMENTS
TOPICS 表:id(自动递增),主题行。
USERS 表:用户名,电子邮件,名字和姓氏以及其他一些不相关的行
POSTS 表:id(自动递增),post-title,post-body,topic-id,user-id,post-date,updated-date,updated-by(将包含发表最新评论的人的用户ID
评论表:ID(自动递增),post-id,用户ID和评论
在我想要的主论坛页面上:
这是我到目前为止的查询:
SELECT topics.id AS topic-id,
topics.topic,
post-user.id AS user-id,
CONCAT_WS(' ', post-user.first-name, post-user.last-name) AS name,
recent-post.id AS post-id,
post-num.post-total,
recent-post.title AS post-title,
recent-post.update_date AS updated-date,
recent-post.updated-by AS updated-by
FROM topics
JOIN (SELECT posts.topic-id,
COUNT(*) AS post-total
FROM POSTS
WHERE posts.topic-id = topic-id
GROUP BY posts.topic-id) AS post-num ON topics.id = post-num.topic-id
JOIN (SELECT posts.*
FROM posts
ORDER BY posts.update-date DESC) AS recent-post ON topics.id = recent-post.topic-id
JOIN (SELECT users.*,
posts.user-id
FROM users, posts
WHERE posts.user-id = users.id) as post-user ON recent-post.user_id = post-user.id
GROUP BY topics.id
此查询几乎可以正常运行,因为它将获取有帖子的主题的所有信息。 但它没有返回没有任何帖子的主题。
我确信查询效率低且错误,因为它对posts表进行了两次子选择,但这是我能够达到目标的唯一方法。
答案 0 :(得分:1)
ORDER BY
是没有意义的。topic_id
,user_id
等命名为(而不是每个表中的“id
”),并且您不必在选择中对它们进行别名-list。首先获得每个主题的最新帖子,以及相关的用户信息:
SELECT t.topic_id, t.topic,
u.user_id, CONCAT_WS(' ', u.first_name, u.last_name) AS full_name,
p.post_id, p.title, p.update_date, p.updated_by
FROM topics t
INNER JOIN
(posts p INNER JOIN users u ON (p.updated_by = u.user_id))
ON (t.topic_id = p.topic_id)
LEFT OUTER JOIN posts p2
ON (p.topic_id = p2.topic_id AND p.update_date < p2.update_date)
WHERE p2.post_id IS NULL;
然后在单独的,更简单的查询中获取每个主题的帖子数。
SELECT t.topic_id, COUNT(*) AS post_total
FROM topics t LEFT OUTER JOIN posts p USING (topic_id)
GROUP BY t.topic_id;
合并应用程序中的两个数据集。
答案 1 :(得分:0)
为了确保您获得没有帖子的主题的结果,您需要使用LEFT JOIN而不是JOIN来进行主题和下一个表之间的第一次连接。 LEFT JOIN表示“总是为左表中的每一行返回一个结果集行,即使与右表没有匹配。”
现在要走了,但我稍后会尝试查看效率问题。
答案 2 :(得分:0)
我在子查询中使用left join
来撤回正确的主题,然后你可以在其外做一些小工作来获取一些用户信息。
select
s.topic_id,
s.topic,
u.user_id as last_updated_by_id,
u.user_name as last_updated_by,
s.last_post,
s.post_count
from
(
select
t.id as topic_id,
t.topic,
t.user_id as orig_poster,
max(coalesce(p.post_date, t.post_date)) as last_post,
count(*) as post_count --would be p.post_id if you don't want to count the topic
from
topics t
left join posts p on
t.id = p.topic_id
group by
t.topic_id,
t.topic,
t.user_id
) s
left join posts p on
s.topic_id = p.topic_id
and s.last_post = p.post_date
and s.post_count > 1 --0 if you're using p.post_id up top
inner join users u on
u.id = coalesce(p.user_id, s.orig_poster)
order by
s.last_post desc
此查询确实介绍了coalesce
和left join
,它们是非常好的概念。对于两个参数(如此处使用的那样),您也可以在MySQL中使用ifnull
,因为它在功能上是等效的。
请记住,这是MySQL独有的(如果您需要移植此代码)。其他数据库具有其他功能(SQL Server中为isnull
,Oracle中为nvl
等,等等)。我使用coalesce
以便我可以将此查询保持为ANSI-fied。
答案 3 :(得分:0)
这是一个非常复杂的查询。您应该注意,JOIN语句会将您的主题限制为有帖子的主题。如果主题没有帖子,则JOIN语句会将其过滤掉。
尝试以下查询。
SELECT *
FROM
(
SELECT T.Topic,
COUNT(AllTopicPosts.ID) NumberOfPosts,
MAX(IFNULL(MostRecentPost.Post-Title, '') MostRecentPostTitle,
MAX(IFNULL(MostRecentPostUser.UserName, '') MostRecentPostUser
MAX(IFNULL(MostRecentPost.Updated_Date, '') MostRecentPostDate
FROM TOPICS
LEFT JOIN POSTS AllTopicPosts ON AllTopicPosts.Topic_Id = TOPICS.ID
LEFT JOIN
(
SELECT *
FROM Posts P
WHERE P.Topic_id = TOPICS.id
ORDER BY P.Updated_Date DESC
LIMIT 1
) MostRecentPost ON MostRecentPost.Topic_Id = TOPICS.ID
LEFT JOIN USERS MostRecentPostUser ON MostRecentPostUser.ID = MostRecentPost.User_Id
GROUP BY T.Topic
)
ORDER BY MostRecentPostDate DESC