2010-08-03 222 views
2

如果我在帖子和标签之间存在多对多关系,如何选择包含特定标签的帖子?SQL如何查询多对多关系

更新:

我遇到的问题是,因为在那里tag.name = 'xxx',只有标签被选中。我想要的是选择具有指定标签的所有帖子,tgt与他们的所有标签,例如。

Post 1 -> tag1, tag2 
Post 2 -> tag1, tag3 
Post 3 -> tag2, tag3 

目前我所得到的是

Post 1 -> tag2 // missing tag1 
Post 3 -> tag2 // missing tag3 
+0

查看更新.... – cletus 2010-08-03 15:51:48

+5

鉴于所选答案似乎是一个SQL解决方案而不是DQL,这个问题的标题不应该从DQL更改为SQL吗?我来到这里寻找一种方法来完成多对多的DQL查询,但这里没有任何内容。 – 2012-03-29 20:50:47

回答

4

假设这些表:

  • 帖子ID,作者,日期,内容
  • 标签ID,名称
  • PostTags :post_id,tag_id

最后一个表通常被称为连接表,并促进了文章和标签之间的多对多关系。

SELECT p.* 
FROM posts p 
JOIN posttags pt ON p.id = pt.post_id 
JOIN tags t ON pt.tag_id = t.id 
WHERE t.name = 'sql' 

基本上,认为许多一对多的关系,两个一对多关系的,因为这是他们如何在正常的RDBMS实现。所以上面的查询有一个从Posts到PostTag的一对多连接,另一个从Tags到PostTag。

我创建的PostTags表具有复合主键,即(post_id, tag_id)。这种组合将是独一无二的。许多冷遇组合键,因此您会经常看到有人创建一个主键列:

  • PostTags:ID,POST_ID,TAG_ID

两种方法是罚款。这在很大程度上是一个哲学上的差异。

更新:,如果你想选择所有具有特定标签,所有的标签这些帖子有那么帖子:

SELECT p.* 
FROM posts p 
JOIN posttags pt ON p.id = pt.post_id 
JOIN tags t ON pt.tag_id = t.id 
WHERE p.id IN 
    (SELECT post_id 
    FROM PostTags pt 
    JOIN tags t ON pt.tag_id = t.id 
    WHERE t.name = 'xyz') 

另一种方式来做到这一点:

SELECT p.* 
FROM posts p 
JOIN posttags pt ON p.id = pt.post_id 
JOIN tags t ON pt.tag_id = t.id 
WHERE EXISTS 
    (SELECT post_id 
    FROM PostTags pt 
    JOIN tags t ON pt.tag_id = t.id 
    WHERE t.name = 'xyz' 
    AND pt.post_id = p.id) 

哪个性能更好将需要测试,并可能因数据库供应商和版本而异。一个好的优化器(如Oracle)可能会优化它们以执行相同的操作。其他人可能不会。

现在,这将让你回行这样的:

Post 1, tag 1 
Post 1, tag 2 
Post 3, tag 2 
Post 3, tag 3 

所以你需要把它们混合起来,最好是在应用程序逻辑,而不是SQL。一些关系数据库管理系统有这种类型的供应商特定的扩展,比如MySQL的GROUP_CONCAT()函数。

+0

我只是'选择帖子,标签从应用程序\模型\发布帖子INNER JOIN post.tags tags' b4我看到这篇文章,它似乎工作。没有标签名称tho。你和我的有什么不同吗? – 2010-08-03 10:38:28

+0

我还发现,由于where子句,只有在那里指定的标签被选中。我想用该标签获取帖子。但对于匹配的帖子,我想要所有,而不仅仅是指定的标签。也许我在子查询上工作 – 2010-08-03 10:45:02

+0

@jiewmeng我不明白你的问题。 – cletus 2010-08-03 11:30:08