SQL - 仅返回每个记录一次

时间:2011-01-01 05:34:55

标签: sql tags

这是我的表格:

tblBusiness
BusinessID, BusinessName

tblTags
TagID, Tag

tblBusinessTagLink
BusinessID, TagID

任何企业都可以应用多个代码。现在假设用户正在过滤,以便他们只找到标记为“办公用品”和“技术”的商家

我应该使用哪种SQL语句?我的桌子有比我在这里展示的更好的设计吗?

3 个答案:

答案 0 :(得分:2)

SELECT
  b.BusinessId,
  b.BusinessName 
FROM
  tblBusiness AS b
  INNER JOIN tblBusinessTagLink AS l ON l.BusinessId = b.BusinessId
  INNER JOIN tblTags            AS t ON t.TagId      = l.TagId
WHERE
  t.TagName IN ('Technology', 'Office Supplies')
GROUP BY
  b.BusinessId,
  b.BusinessName 

选择其中任何一个类别中的所有商家。要仅选择两个类别中的那些,您可以附加

HAVING COUNT(*) = 2

您正在使用的方法(三个表来表示m:n关系)是解决此任务的标准方法,您可以保留它。

就个人而言,我不会对表名使用“匈牙利表示法”(即没有“tbl”)而且我不会使用复数表名(即不是“标签”),尤其是当其他表也不是复数时。 / p>


回答下面的第一条评论:

对于较大的数据集,此查询的性能依赖于索引。当然,所有主键都需要索引。在tblBusinessTagLink中,您应该有一个覆盖两个字段的复合索引和一个不在复合索引中首先出现的字段的附加索引。

WHERE keywords LIKE '%technology%'这个想法很糟糕,主要是因为除了字段搜索之外的任何LIKE条件都不能使用索引(即,随着数据集的增长,性能会迅速降低),部分原因是因为它应该WHERE ','+keywords+',' LIKE '%,technology,%'开始,否则你会得到部分匹配/误报。

此外,TagId查询可能会更有效率。这样你就可以完全从JOIN中删除一个表:

FROM 
  tblBusiness AS b 
  INNER JOIN tblBusinessTagLink AS l ON l.BusinessId = b.BusinessId 
WHERE 
  l.TagId IN (1, 2)

如果您打算按TagName进行查询,那么此字段的索引也是绝对必要的。

答案 1 :(得分:0)

您可以使用简单的JOIN获取记录

SELECT t.Tag, b.BusinessName 
FROM tblBusiness b, tblTags t, tblBusinessTagLink l
WHERE t.TagID = l.TagID 
AND l.BusinessID = b.BusinessID 
AND t.Tag = 'Office Supplies'

答案 2 :(得分:-1)

您可以使用INTERSECT设置操作合并2个查询(一个用于'Office Supplies',一个用于'Technology')。

但是,如果您使用的是MySQL(不支持INTERSECT),则可以使用UNION ALL并使用'HAVING COUNT(*)= 2'like this


编辑:

你也可以使用没有UNION ALL的第二个选项,如下所示:

select Name from tblBusiness
left join tblBusinessTagLink on tblBusinessTagLink.BusinessID = tblBusiness.ID
left join tblTags on tblTags.TagID = tblBusinessTagLink.TagID
where Tag = 'Office Supplies' or Tag = 'Technology'
group by name
having count(Name) = 2;