这是我的数据库架构:
Post:
id
title
body
date
Tag:
id
title
Post_Tag:
id
id_post
id_tag
Comment:
id
id_post
body
date
帖子和标签之间有很多关系。
我需要在主页上打印最新的10个帖子:
<a href="post.php?id=ID_POST">POST_TITLE</a>
POST_BODY
<a href="tag.php?id=ID_TAG_1"> TAG_TITLE_1 </a>
<a href="tag.php?id=ID_TAG_2"> TAG_TITLE_2 </a>
<a href="tag.php?id=ID_TAG_3"> TAG_TITLE_3 </a>
COMMENTS_NUMBER
最好的查询是什么?
我试过这个,但是效果不好因为每个帖子都有多行:
SELECT p.title, p.id, p.date, t.title, t.id, COUNT(c.id)
FROM post p
LEFT JOIN post_tag pt
ON p.id=pt.id_post
LEFT JOIN tag t
ON t.id=pt.id_tag
LEFT JOIN comment c
ON p.id=c.id_post
GROUP BY p.title, p.id, p.date, t.title
ORDER BY p.date DESC
答案 0 :(得分:3)
您可能不希望将此作为单个查询执行,但理论上您可以这样做。
SELECT
Post.id AS post_id,
Post.title AS post_title,
Post.body AS post_body,
GROUP_CONCAT(CONCAT(Tag.id, "|", Tag.title) SEPARATOR '#') AS tags,
COUNT(Comment.id) AS comment_count
FROM Post
LEFT JOIN Comment ON Post.id = Comment.id_post
LEFT JOIN Post_Tag ON Post.id = Post_Tag.id_post
LEFT JOIN Tag ON Tag.id = Post_Tag.id_tag
GROUP BY Post.id
ORDER BY Post.date ASC
我没有检查过这个,因为我无法访问您的数据,但它应该可以正常工作。您需要手动拆分标签,这些标签将以“ID | TITLE#ID | TITLE”的格式显示,但这是唯一需要的额外处理。
或者,您可以通过在两个单独的查询之间拆分此工作负载来避免标记的GROUP_CONCAT:
SELECT
Post.id AS post_id,
Post.title AS post_title,
Post.body AS post_body,
COUNT(Comment.id) AS comment_count
FROM Post
LEFT JOIN Comment ON Post.id = Comment.id_post
GROUP BY Post.id
ORDER BY Post.date ASC
从这里,您将存储所有单独的post_id,并在第二个查询中使用它们,如下所示:
SELECT
Tag.id,
Tag.title
FROM Post_Tag
INNER JOIN Tag ON Post_Tag.id_tag = Tag.id
WHERE Post_Tag.id_post IN (**comma-separated list of Post IDs**)
这意味着您可以执行两个查询,否则您必须执行一个查询以获取所有帖子,然后另一个查找标签的每个帖子 - 这是一个N + 1查询,而我上面提出的是解决这个问题的常用方法。
答案 1 :(得分:1)
如果我理解正确,那么您正试图制作一个“带标签和评论的帖子”系统,其关系如下:
根据Stephen Orr's answer的建议,您应该为代码执行GROUP_CONCAT
以避免重复发帖。你还需要做一些小的后期处理来格式化标签,除非你只是想要标签标题,但那就是它。
这是一个例子
SELECT
p.ID,
p.title,
p.body,
p.c_date,
GROUP_CONCAT(DISTINCT CONCAT_WS('|', CAST(t.ID AS CHAR), t.title) SEPARATOR ';') AS tags,
COUNT(c.ID) AS comments
FROM Post p
LEFT JOIN Comment c ON p.ID = c.id_post
LEFT JOIN Post_Tag pt ON p.ID = pt.id_post
LEFT JOIN Tag t ON pt.id_tag = t.ID
GROUP BY p.ID, p.title, p.body, p.c_date
ORDER BY p.c_date DESC
请注意,我在标记ID上使用显式类型转换。
以下是对GROUP_CONCAT
和CONCAT_WS
的一些引用。