让我们拿SO网站。它有问题和问题有它的标签。我的问题是,什么是显示问题及其标签的最佳方式。假设他们在不同的表格中。你可以使用SELECT JOIN查询问题及其标签吗?
SELECT * FROM questions RIGHT JOIN tags ON questions.id = tags.question_id
但也有不止一个标签,所以我们怎么会一起显示出来?或者我们只需要做2 SELECTs?因为如果是的话,那么它会花费很多资源,因为我们在一个页面中显示多个问题。
让我们拿SO网站。它有问题和问题有它的标签。我的问题是,什么是显示问题及其标签的最佳方式。假设他们在不同的表格中。你可以使用SELECT JOIN查询问题及其标签吗?
SELECT * FROM questions RIGHT JOIN tags ON questions.id = tags.question_id
但也有不止一个标签,所以我们怎么会一起显示出来?或者我们只需要做2 SELECTs?因为如果是的话,那么它会花费很多资源,因为我们在一个页面中显示多个问题。
首先SO至少需要一个标记,以便不需要right join
,它实际上应该是一个left outer join
,如果你想要做什么,我觉得你这样做......
正如你所说,可以有更多而不是一个标签,这表明我们需要or
或in
或返回多个行或进行某种类型的字符串聚合。
但是,这不会是一个非常好的数据模型,因为您仍然需要知道该问题的标签。所以,最好的办法是将标签存储在posts
表格中,而不用担心tag_id
混乱。
这实际上是这样做的。
您的查询(实际上工作)然后是:
select Tags
from Posts
where Id = ?
Tags
是nvarchar(150)
,这对于问题的标签的分隔列表,在你看到他们对你的问题,如果相同的格式这很有趣!
无论何时输入新标签,它都会自动创建标签,并使用同义词来确保人们的错误拼写得到纠正。所以,有一个Tags
表Id | 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
我不认为这是什么,所以实际上没有 - 我甚至不知道为什么会出现一个PostTags
或Tags
表,因为任何标记都是允许的,不需要执行外键查找来检查标记是否存在。而且没有必要以这种规范化的方式存储关系。您只需要Posts
列中的Tags
列和TagSynonyms
表以确保同义词系统正常工作。然后,如果主键不是Id
而是TagName
,则只需要查找一次。
假设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_names
和tag_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']);
的获取JSON对象下一个给你一个具体问题的所有标签。
SELECT * FROM `questions` q INNER JOIN `tags` t ON q.id = t.question_id;
这假定您的标签表是标签和问题之间的多对多。
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
您的标签表是您的问题表和标签表之间的多对多吗? – nnichols 2012-03-03 21:16:14