帮助多对多过滤查询

时间:2011-01-18 06:19:11

标签: sql-server database database-design query-optimization

我正在试图弄清楚如何在我的数据库中高效实现标记。

一种方法是有一个文章表(比方说Articles, ArtID int PK, ArtText varchar(max))和一个标签表(让我们说Tags, TagID int PK, TagTitle varchar(15))。然后我将创建一个连接表来创建文章和标签之间的多对多关系(假设ArticleTags, ArtID int, TagID int (compound primary key)

我的第一个问题是,编写查询以查找与给定标记关联的所有文章的最佳方法是什么?如果我想返回组合数据,我知道连接,但如果我只想知道哪些文章行与特定标签相关联,那么最有效的查询是什么。在现实生活中,我需要找到带有多个标签的文章,最好还能找到与特定标签无关的文章。

我的第二个问题是我的Tags表是否应该有一个int PK?使用TagTitle作为主键更有意义吗?

2 个答案:

答案 0 :(得分:2)

(1)

(a)具有特定标签的物品:

SELECT columns FROM Articles WHERE EXISTS 
  (SELECT null FROM ArticleTags at 
    WHERE at.ArtID = Articles.ArtID AND at.TagID=x)

(b)没有特定标签的物品:

SELECT columns FROM Articles WHERE NOT EXISTS 
  (SELECT null FROM ArticleTags at 
    WHERE at.ArtID = Articles.ArtID AND at.TagID=x)

(2)如果您只是获取与文章关联的标签列表,则使用TagTitle会更快,但对于大多数其他可能的操作,代理int将更快。

答案 1 :(得分:0)

1a)我的第一个问题是,编写查询以查找与给定标记关联的所有文章的最佳方法是什么?

select ArtID  -- if only IDs are required
from ArticleTags
where TagID=1  -- or use the text (where tagtitle='x')

select A.*
from ArticleTags T inner join Articles A on A.ArtID = T.ArtID
where T.TagID=1

1b)在现实生活中,我需要找到包含多个标签的文章

-- has tags 1,3 and 8
select T1.ArtID
from ArticleTags T1
inner join ArticleTags T2 on T1.ArtID = T2.ArtID and T2.TagID = 3
inner join ArticleTags T3 on T1.ArtID = T3.ArtID and T3.TagID = 8
where T1.TagID=1
  -- or use the text (tagtitle='x') on each filter

在某些情况下,此表单的工作速度更快。可以连接此前一个或前一个来获取文章记录。

select ArtID
from (
    select T1.ArtID from ArticleTags T1 where T1.TagID=1
    union all
    select T2.ArtID from ArticleTags T2 where T2.TagID=3
    union all
    select T3.ArtID from ArticleTags T3 where T3.TagID=8
) X
group by ArtID
having count(ArtID) = 3

1c)并且找到与特定标签无关的文章会很好。

select A.*
from Articles A
left join ArticleTags T on T.ArtID = A.ArtID and T.TagTitle = 'nomatch'
where T.ArtID is null

2)我的第二个问题是我的Tags表是否应该有一个int PK?使用TagTitle作为主键更有意义吗?

我坚定地说,每个表应该有一个连续的,无意义的整数ID。它减少了存储空间(FK来自其他表),int lookup / range合并总是比varchar快。