如何在一个查询中显示与所有反馈相关的所有标签

时间:2010-01-19 12:21:07

标签: sql mysql tags

我正在尝试编写一个sql查询,该查询获取与页面上显示的每个主题相关的所有标记。

像这样

TITLE: feedback1
POSTED BY: User1
CATEGORY: category1
TAGS: tag1, tag2, tag3

TITLE: feedback2
POSTED BY: User2
CATEGORY: category2
TAGS: tag2, tag5, tag7,tag8

TITLE: feedback3
POSTED BY: User3
CATEGORY: category3
TAGS: tag1, tag5, tag6, tag3

标签与主题的关系是多对多的。

现在我首先从“主题”表中获取所有主题,并获取每个主题的相关标记,我循环返回的主题数组以获取标记。 但是这种方法在速度方面非常昂贵而且效率也不高。

请帮我写这个SQL查询。

查询获取所有主题及其信息如下:

SELECT
    tbl_feedbacks.pk_feedbackid as feedbackId,
    tbl_feedbacks.type as feedbackType,
    DATE_FORMAT(tbl_feedbacks.createdon,'%M %D, %Y') as postedOn,
    tbl_feedbacks.description as description,
    tbl_feedbacks.upvotecount as upvotecount,
    tbl_feedbacks.downvotecount as downvotecount,
    (tbl_feedbacks.upvotecount)-(tbl_feedbacks.downvotecount) as totalvotecount,
    tbl_feedbacks.viewcount as viewcount,
    tbl_feedbacks.title as feedbackTitle,
    tbl_users.email as userEmail,
    tbl_users.name as postedBy,
    tbl_categories.pk_categoryid as categoryId,
    tbl_clients.pk_clientid as clientId
FROM
    tbl_feedbacks
LEFT JOIN tbl_users
    ON ( tbl_users.pk_userid = tbl_feedbacks.fk_tbl_users_userid )
LEFT JOIN tbl_categories
    ON ( tbl_categories.pk_categoryid = tbl_feedbacks.fk_tbl_categories_categoryid )
LEFT JOIN tbl_clients
    ON ( tbl_clients.pk_clientid = tbl_feedbacks.fk_tbl_clients_clientid )
WHERE
    tbl_clients.pk_clientid = '1'

当您需要显示与单个页面上显示的每个主题相关的所有标记时,应该遵循的最佳做法是什么。


如何更改上面的sql查询,以便使用单个查询获取所有标记以及主题的相关信息。

我试图实现的演示类似于stackoverflow的'questions'页面。 所有信息(标签+正在显示的每个主题的信息)都会正确显示。

由于

1 个答案:

答案 0 :(得分:3)

要做到这一点,我会有三个表:

Topics
  topic_id
  [whatever else you need to know for a topic]
Tags
  tag_id
  [etc]
Map
  topic_id
  tag_id

select t.[whatever], tag.[whatever]
  from topics t
  join map m on t.topic_id = m.topic_id
  join tags tag on tag.tag_id = m.tag_id
  where [conditionals]

在地图表上设置分区和/或索引,以最大限度地提高查询速度。例如,如果您拥有的主题多于标签,请在主题上对表进行分区。然后,每次你获取一个主题的所有标签,它将从1个区域读取1,不需要寻找。确保在_id上标记了主题和标签。

使用“解释计划”工具。 (我不熟悉mysql,但我假设有一些工具可以告诉你如何运行查询,所以你可以优化它)

编辑:

所以你有以下表格:

tbl_feedbacks
tbl_users
tbl_categories
tbl_clients
tbl_tags
tbl_topics
tbl_topics_tags

您提供的查询作为起点显示了反馈,用户,类别和客户之间的相互关系。

我假设tbl_topics_tags包含标签和主题的FK,显示哪个主题具有哪个标签。这是对的吗?

(反馈,用户,类别和客户)对主题或标签有什么影响?或者,任何主题或标签都有FK到最初的4?

一旦我知道这一点,我将能够展示如何修改查询。

编辑#2

有两种不同的方法:

简单的方法就是加入你的FK。这将为每个标签提供一行。通过这种方式将SQL组合在一起会更加容易和灵活。如果您使用其他语言来获取查询结果并将其转换为将其呈现给用户,则此方法更好。如果不出意外,它将会更加明显,并且将更容易调试和维护。

但是,您可能希望查询结果的每一行都包含一个反馈(以及随之而来的标记)。

SQL joining question< - 这是我发布的关于如何执行此操作的问题。我接受的答案是仅甲骨文答案AFAIK,但还有其他非甲骨文答案。

调整Kevin的答案(应该在SQL92兼容系统中有效):

select 
[other stuff: same as in your post],
 (select tag
  from tbl_tag tt
  join tbl_feedbacks_tags tft on tft.tag_id = tt.tag_id
  where tft.fk_feedbackid = tbl_feedbacks.pk_feedbackid
  order by tag_id
  limit 1
  offset 0 ) as tag1,
 (select tag
  from tbl_tag tt
  join tbl_feedbacks_tags tft on tft.tag_id = tt.tag_id
  where tft.fk_feedbackid = tbl_feedbacks.pk_feedbackid
  order by tag_id
  limit 1
  offset 1 ) as tag2,
 (select tag
  from tbl_tag tt
  join tbl_feedbacks_tags tft on tft.tag_id = tt.tag_id
  where tft.fk_feedbackid = tbl_feedbacks.pk_feedbackid
  order by tag_id
  limit 1
  offset 2 ) as tag3
from [same as in the OP]

这应该可以解决问题。

注意:

这将拉出前三个标签。 AFAIK,没有办法拥有任意数量的标签。您可以通过复制和粘贴查询的更多部分来扩展显示的标记数量。确保增加offset设置。

如果这不起作用,你可能不得不写另一个问题,重点是如何在mysql中进行数据透视。我从来没有使用过mysql,所以我只是猜测这会基于其他人告诉我的内容。

一个提示:如果您删除所有额外的细节,通常会更加关注您的问题。在我上面链接的问题中,我真的加入了4到5个不同的表,有许多不同的字段。但我把它剥离到我不知道的部分(如何让oracle将我的结果聚合成一行)。我知道一些东西,但如果你把问题减少到必需品,你通常可以做得比一个人好得多。