2012-03-03 41 views
1

让我们拿SO网站。它有问题和问题有它的标签。我的问题是,什么是显示问题及其标签的最佳方式。假设他们在不同的表格中。你可以使用SELECT JOIN查询问题及其标签吗?

SELECT * FROM questions RIGHT JOIN tags ON questions.id = tags.question_id

但也有不止一个标签,所以我们怎么会一起显示出来?或者我们只需要做2 SELECTs?因为如果是的话,那么它会花费很多资源,因为我们在一个页面中显示多个问题。

+0

您的标签表是您的问题表和标签表之间的多对多吗? – nnichols 2012-03-03 21:16:14

回答

1

首先SO至少需要一个标记,以便不需要right join,它实际上应该是一个left outer join,如果你想要做什么,我觉得你这样做......

正如你所说,可以有更多而不是一个标签,这表明我们需要orin或返回多个行或进行某种类型的字符串聚合。

但是,这不会是一个非常好的数据模型,因为您仍然需要知道该问题的标签。所以,最好的办法是将标签存储在posts表格中,而不用担心tag_id混乱。

这实际上是这样做的。

您的查询(实际上工作)然后是:

select Tags 
    from Posts 
where Id = ? 

Tagsnvarchar(150),这对于问题的标签的分隔列表,在你看到他们对你的问题,如果相同的格式这很有趣!

无论何时输入新标签,它都会自动创建标签,并使用同义词来确保人们的错误拼写得到纠正。所以,有一个TagsId | TagName和一个TagSynonoyms表,(我不知道维基总结保存在哪里)。然后,您可以在写入Posts表之前分配标签检查以查看它是否有同义词并进行更正。

虽则回答你的问题,查询会(也实际工作):

select p.*, t.TagName 
    from Posts p 
    join PostTags pt 
    on p.Id = pt.PostId 
    join Tags t 
    on pt.TagId = t.Id 

我不认为这是什么,所以实际上没有 - 我甚至不知道为什么会出现一个PostTagsTags表,因为任何标记都是允许的,不需要执行外键查找来检查标记是否存在。而且没有必要以这种规范化的方式存储关系。您只需要Posts列中的Tags列和TagSynonyms表以确保同义词系统正常工作。然后,如果主键不是Id而是TagName,则只需要查找一次。

4

假设tags表中有一个name列,我会用GROUP_CONCAT函数。

SELECT questions.*, 
     GROUP_CONCAT(DISTINCT tags.name -> ORDER BY tags.id SEPARATOR ',') AS `tag_names`, 
     GROUP_CONCAT(DISTINCT tags.id -> ORDER BY tags.id SEPARATOR ',') AS `tag_ids` 
FROM questions 
     RIGHT JOIN tags 
     ON questions.id = tags.question_id 

这将显示2柱tag_namestag_ids其中值将是逗号分隔。当我们获取值时,我们可以将其分解并获得真实值。

while($row=mysql_fetch_assoc($result)){ 
     $tag_names = explode("," $row['tag_names']; 
     $tag_ids = explode("," $row['tag_ids']; 
     $tags = array_combine($tag_ids, $tag_names); 
    } 

现在$tags成为一个关联数组,其关键字是标记ID,值是标记名称。

如果使用下面的表达式,它会创建一个JSON。但不依赖于它,如果你的标签名称有哪些需要转义的任何字符(例如"

Concat('{', GROUP_CONCAT(Concat('"', tags.id, '":"', tags.name, '"') 
       ORDER BY 
       tags.id), '}') AS `tag_o` 

通过$tags = json_decode($row['tag_o']);

0

的获取JSON对象下一个给你一个具体问题的所有标签。

SELECT * FROM `questions` q INNER JOIN `tags` t ON q.id = t.question_id; 
0

这假定您的标签表是标签和问题之间的多对多。

SELECT questions.*, GROUP_CONCAT(CONCAT(tag.id, '::', tag.name)) 
FROM questions 
LEFT JOIN tags 
    ON questions.id = tags.question_id 
LEFT JOIN tag 
    ON tags.tag_id = tag.id 
GROUP BY questions.id