0

这是我的数据库架构:

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
4

2 回答 2

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 查询,而我上面建议的是解决该问题的常见方法。

于 2013-05-17T08:11:59.157 回答
1

如果我理解正确,您正在尝试制作一个“带有标签和评论的帖子”系统,具有以下关系
关系


一个查询来统治他们

正如斯蒂芬奥尔的回答所建议的那样,您应该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

于 2013-05-17T12:19:38.277 回答