SQLServer选择连接并返回多个连接记录与值匹配的结果

时间:2015-06-26 18:47:18

标签: sql-server join

说我有2张桌子:

+-------------+
| Id.   Name. |
+-------------+
| 1.    Hello |
| 2.    World |
+-------------+

PersonAttribute

+------------------------------------------------------+
| Id.   PersonId.     AttributeName   AttributeValue   |
+------------------------------------------------------+
|  1.     1.             Gender             M          |
|  2.     1.             WearsGlasses       Y          |
|  3.     1.             LikesColorGreen    N          |
|  4.     2.             Gender             F          |
|  5.     2.             WearsGlasses       N          |
|  6.     2.             LikesColorGreen    Y          |
+------------------------------------------------------+

如果我想返回我希望寻找符合仲裁属性集的人

的结果,该怎么办?

所以我有两个问题:

我如何搜索具有以下查询的人:性别= F和LikesColorGreen = Y

如果我想让查询允许任意属性集,该怎么办? 例如:查询表指定

QueryAttributeName QueryValue

+----------------------------------+
|  1. LikesColorGreen           N  |
|  2. WearsGlasses              Y  |
|  3. Gender                    F  |
+----------------------------------+

我对“Gender = F和LikesColorGreen = Y”的一个查询是:

select * from Person p
Join PersonAttribute pa on p.id = pa.PersonId and pa.AttributeName = Gender and AttributeValue = F
interset
select * from Person p
Join PersonAttribute pa on p.id = pa.PersonId and pa.AttributeName = LikesColorGreen and AttributeValue = Y

是否有更好的查询可以获得这个?

什么是这样的查询?

2 个答案:

答案 0 :(得分:1)

你可以试试这个:

 select pid from atts where
  (aname='Gender' and avalue='M') 
  or      
  (aname='WearsGlasses' and avalue='Y')
  or
  (aname='LikesColorGreen' and avalue='Y')
   group by pid having COUNT(*)=3

可以轻松扩展查询以检查更多属性。

性能可能是一个问题,但是使用这种数据结构,您不能期望太多。

如果您有要匹配的表格,可以尝试:

select pid from atts a join att_match m 
on a.aname=m.aname and a.avalue = m.avalue
group by pid having COUNT(*)= (select count(*) from att_match);

它匹配你的"匹配crietria"中的所有条件。表。

答案 1 :(得分:1)

您尝试实施的内容称为Entity-Attribute-Value Model (EAV)。它可以为您提供一些灵活性,满足客户的独特需求,而无需修改应用程序代码和数据库结构,但它也有它的缺点。

如果您为属性创建另一个表,那么可以提高性能的一件事就是在[AttributeID]中使用PersonAttribute而不是文本。这将使您的连接更快,并减少表的大小,这可能会变得非常大,具体取决于您添加的实体和属性的数量。

示例中的所有属性都是二进制值(y / n,m / f ......等)。如果您的大多数属性都是位标志,那么您可能会在int,bigint或varbinary字段中存储一些数据,并且配置表会分配哪些位映射到您的属性。然后检查位掩码以查明记录是否与查询参数匹配。您还可以使用位字段和属性表进行混合。

否则,使用AND获得所有属性匹配的最快查询可能只是具有适当索引的标准连接:

select distinct Person.*
from Person
join PersonAttribute att1
on Person.PersonID=att1.PersonID
  and att1.attId = 1 --maps to AGE
  and att1.AttributeValue BETWEEN 30 AND 40
join PersonAttribute att2
on Person.PersonID=att2.PersonID
  and att2.attId = 1 --maps to Income
  and att2.AttributeValue < 200000
join ... etc.