【问题标题】:MySQL implement search based on multiple filtersMySQL实现基于多个过滤器的搜索
【发布时间】: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
------------------------------------

【问题讨论】:

  • 拥有一些测试数据和预期的查询输出真的很有帮助,这样我们就可以尝试各种查询,直到得到正确的答案。

标签: mysql sql search filtering


【解决方案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 不可能同时是 12
  • 实际上,现在看来您几乎成功了。您可能应该将“主要”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

    即这种动物没有尾巴,有冷杉,没有鳞片,而且是棕色的。

    此键可以轻松过滤与该条件匹配的所有项目,并且无需对查询进行额外的代码更改即可添加新条件。查看位运算符以使用这些键。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-18
      • 1970-01-01
      • 1970-01-01
      • 2019-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-06
      相关资源
      最近更新 更多