SQL-每个记录只返回一次

SQL-每个记录只返回一次,sql,tags,Sql,Tags,这是我的桌子: tblBusiness BusinessID, BusinessName tblTags TagID, Tag tblBusinessTagLink BusinessID, TagID 任何业务都可以应用多个标记。现在让我们假设一个用户正在向下筛选,以便他们只找到标记为“办公用品”和“技术”的企业 我应该使用什么SQL语句?我的表是否有比我在这里介绍的更好的设计?您可以使用简单连接来获取记录 SELECT t.Tag, b.BusinessName FROM tblBus

这是我的桌子:

tblBusiness
BusinessID, BusinessName

tblTags
TagID, Tag

tblBusinessTagLink
BusinessID, TagID
任何业务都可以应用多个标记。现在让我们假设一个用户正在向下筛选,以便他们只找到标记为“办公用品”和“技术”的企业


我应该使用什么SQL语句?我的表是否有比我在这里介绍的更好的设计?

您可以使用简单连接来获取记录

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'

您可以使用简单连接来获取记录

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'
您可以使用set操作合并两个查询(一个用于“办公用品”,另一个用于“技术”)

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


编辑:

您也可以在不使用UNION的情况下使用第二个选项,如下所示:

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;
您可以使用set操作合并两个查询(一个用于“办公用品”,另一个用于“技术”)

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


编辑:

您也可以在不使用UNION的情况下使用第二个选项,如下所示:

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;
这将选择属于其中一个类别的所有业务。要仅选择这两个类别中的类别,可以附加

HAVING COUNT(*) = 2
您使用的方法(三个表表示m:n关系)是解决此任务的标准方法,您可以保留它

就我个人而言,我不会对表名使用“匈牙利符号”(即不使用“tbl”),也不会使用复数表名(即不使用“标记”),尤其是在其他表也不是复数的情况下


回答以下第一条评论:

对于较大的数据集,此查询的性能取决于索引。当然,所有主键都需要索引。在
tblBusinessTagLink
中,您应该有一个包含两个字段的复合索引,以及一个附加索引,用于复合索引中不在第一位的字段

WHERE关键字,如“%technology%”
的想法是不好的,主要是因为对于除字段开始搜索以外的任何类似条件,都不能使用索引(即,随着数据集的增长,性能将迅速下降),部分原因是它应该是
WHERE',“+关键字+”,“如“%”,technology,%“
开始,否则您将获得部分匹配/误报

另外,通过
TagId
进行查询可能会更有效率。通过这种方式,您可以完全从联接中删除一个表:

FROM 
  tblBusiness AS b 
  INNER JOIN tblBusinessTagLink AS l ON l.BusinessId = b.BusinessId 
WHERE 
  l.TagId IN (1, 2)
但是,如果您打算按标记名
进行查询,则此字段上的索引也是绝对必要的

这将选择属于其中一个类别的所有业务。要仅选择这两个类别中的类别,可以附加

HAVING COUNT(*) = 2
您使用的方法(三个表表示m:n关系)是解决此任务的标准方法,您可以保留它

就我个人而言,我不会对表名使用“匈牙利符号”(即不使用“tbl”),也不会使用复数表名(即不使用“标记”),尤其是在其他表也不是复数的情况下


回答以下第一条评论:

对于较大的数据集,此查询的性能取决于索引。当然,所有主键都需要索引。在
tblBusinessTagLink
中,您应该有一个包含两个字段的复合索引,以及一个附加索引,用于复合索引中不在第一位的字段

WHERE关键字,如“%technology%”
的想法是不好的,主要是因为对于除字段开始搜索以外的任何类似条件,都不能使用索引(即,随着数据集的增长,性能将迅速下降),部分原因是它应该是
WHERE',“+关键字+”,“如“%”,technology,%“
开始,否则您将获得部分匹配/误报

另外,通过
TagId
进行查询可能会更有效率。通过这种方式,您可以完全从联接中删除一个表:

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

但是,如果您打算按标记名
进行查询,则此字段上的索引也是绝对必要的。

我不了解一些事情。“t”和“b”是您的表名吗?join语句在哪里,或者此sql语句不需要join?另外,您没有指定标记“Technology”。我对它进行了修改,如果选择了两个类别,并且在查询中没有得到任何结果,则尝试返回正确的记录。选择t.Tag,b.BusinessName FROM tblBusiness作为b,tblTags作为t,tblBusinessTagLink作为l,其中(t.Tag='Office Supplies'和t.TagID=[l].[TagID]和l.BusinessID=[b].[BusinessID])和(t.Tag='Technology'和t.TagID=[l].[TagID]和l.BusinessID=[b].[BusinessID]);为什么不使用ANSI连接语法?-1表示隐式连接结构。这是可行的,但这是一种可怕的编码方式。我有几点不懂。“t”和“b”是您的表名吗?join语句在哪里,或者此sql语句不需要join?另外,您没有指定标记“Technology”。我对它进行了修改,如果选择了两个类别,并且在查询中没有得到任何结果,则尝试返回正确的记录。选择t.Tag,b.BusinessName FROM tblBusiness作为b,tblTags作为t,tblBusinessTagLink作为l,其中(t.Tag='Office Supplies'和t.TagID=[l].[TagID]和l.BusinessID=[b].[BusinessID])和(t.Tag='Technology'和t.TagID=[l].[TagID]和l.BusinessID=[b].[BusinessID]);为什么不使用ANSI连接语法?-1表示隐式连接结构。它是有效的,但这是一种可怕的编码方式。谢谢你对匈牙利符号和复数名称的注释。我仍在尝试撤消在构建Access数据库时学到的所有东西。此查询的性能是否会随着业务条目数量的增加而下降?还是随着所选标记数量的增加?或者两者都有?我计划给用户一个选项来选择应用了多达五到六个标记的记录。有时我想知道,如果将标签存储在关键字字段中,这样我就可以从tbl中选择b.BusinessID、b.BusinessName,是否会更快