MySQL实现基于多个过滤器的搜索
Posted
技术标签:
【中文标题】MySQL实现基于多个过滤器的搜索【英文标题】:MySQL implement search based on multiple filters 【发布时间】:2011-09-06 17:06:59 【问题描述】:从下面的表结构中,我希望能够提供基于属性组合的搜索过滤器:
表格:动物属性
id attributeId animalId
1 455 55
2 999 55
3 685 55
4 999 89
5 455 89
6 333 93
7 685 93
8 999 93
--------------------------------
前端会有复选框,例如
Animal options
Colour
[ ] Black (id 685)
[x] Brown (id 999)
Body Covering
[ ] Fur (id 233)
[ ] Scales (id 333)
[x] Feathers (id 455)
我希望上面的复选框能够选择所有棕色并且有羽毛的动物。我可以通过以下查询获取此数据:
SELECT animalId
FROM animalAttributes
WHERE attributeId IN (999,455)
GROUP BY animalId
HAVING COUNT(DISTINCT attributeId) = 2;
我遇到的问题是当从多个过滤器中选择多个选项时,例如
Animal options
Colour
[x] Black (id 685)
[x] Brown (id 999)
Body Covering
[x] Fur (id 233)
[ ] Scales (id 333)
[x] Feathers (id 455)
我希望上面的复选框能够选择所有(黑色OR棕色)并且有(毛皮OR羽毛)的动物.我可以通过以下查询获取此数据:
SELECT animalId
FROM animalAttributes
WHERE
attributeId IN (685,233) ||
attributeId IN (685,455) ||
attributeId IN (999,233) ||
attributeId IN (999,455)
GROUP BY animalId
HAVING COUNT(DISTINCT attributeId) = 2;
如果我想添加额外的过滤器,例如“有尾巴”、“可以飞”、“血型”等,我是否认为我需要计算所有组合 (cartesian product) 并按照和上面的模式一样吗?例如5 个过滤器,每个过滤器选择 1 个或多个选项
attributeId IN (x,x,x,x,x) ||
attributeId IN (x,x,x,x,x) ||
attributeId IN (x,x,x,x,x) ||
...
HAVING COUNT(DISTINCT attributeId) = 5;
其他参考表格
表格:属性
attributeId attributeCategoryId attribute
233 1 Fur
333 1 Scales
455 1 Feathers
685 2 Black
999 2 Brown
-----------------------------------------------
表格:attributeCategories
attributeCategoryId category
1 Body covering
2 Colour
------------------------------------
【问题讨论】:
拥有一些测试数据和预期的查询输出真的很有帮助,这样我们就可以尝试各种查询,直到得到正确的答案。 【参考方案1】:attributeId IN (685,233) ||
attributeId IN (685,455) ||
attributeId IN (999,233) ||
attributeId IN (999,455)
将与您编写时相同: 属性 ID IN (685,233,455,999,233)
试试:
SELECT aa.animalId
FROM animalAttributes aa
LEFT JOIN attributes a ON a.attributeId = aa.attributeId
WHERE
(aa.attributeId IN (685,99) AND a.attributeCategoryId=1) AND
(aa.attributeId IN (223,455) AND a.attributeCAtegoryId=2)
GROUP BY animalId
或者说: (黑色 OR 棕色 AND isColor)AND(毛皮 OR 羽毛 AND isBodyCovering)
Untestet,但你应该明白。
【讨论】:
但是你如何更普遍地做到这一点?如果您添加了另一个类别怎么办 - 那么您将不得不重写您的查询。必须有一个查询允许在不更改查询的情况下添加新的属性数据 如果你用新房间扩建你的房子,你将不得不在你的旧房子里盖一扇门。a.attributeCategoryId
不可能同时是 1
和 2
。
实际上,现在看来您几乎成功了。您可能应该将“主要”AND
(即WHERE (…) **AND** (…)
)更改为OR
并添加HAVING COUNT(DISTINCT a.attributeCategoryId) = 2
。【参考方案2】:
您也可以对交叉路口执行此操作。您可以编写一个查询,为每个过滤器生成一个结果集。然后,您可以将所有结果集相交以得出适合所有过滤器的单个结果集。
这种方法的缺点是您要对数据库执行多个查询。如果由于您的应用程序有大量流量而导致性能成为问题,您可以执行一些内存密集型但不是进程密集型的操作,例如缓存您正在查询的数据库表,以便您只调用一次数据库。
【讨论】:
【参考方案3】:如果我正确理解您的问题,按位键可能会有所帮助。例如,假设每种动物都可以有多个二元选项。例如 has tail = Yes 或 No(0 或 1),Has Scales、Has Fir 等也一样。
然后通过将所有可能的属性添加为二进制选项集,您就可以拥有这个
尾(Y/N) 冷杉(Y/N) 鳞片(Y/N) 棕色(Y/N) 0 1 0 1
即这种动物没有尾巴,有冷杉,没有鳞片,而且是棕色的。
此键可以轻松过滤与该条件匹配的所有项目,并且无需对查询进行额外的代码更改即可添加新条件。查看位运算符以使用这些键。
【讨论】:
以上是关于MySQL实现基于多个过滤器的搜索的主要内容,如果未能解决你的问题,请参考以下文章