说我有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
是否有更好的查询可以获得这个?
什么是这样的查询?
答案 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.