我正在尝试编写一个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'页面。 所有信息(标签+正在显示的每个主题的信息)都会正确显示。
由于
答案 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将我的结果聚合成一行)。我知道一些东西,但如果你把问题减少到必需品,你通常可以做得比一个人好得多。