SQL:按属性列表过滤产品

SQL: Filter products by a list of properties

我有一个叫 products 的 table。 (id, name, price),一个叫做 properties (id, name, type) 的 table 和一个 table 称为 product_properties (id, property_id, product_id, value).

现在,我可以按如下方式筛选产品:

  1. product_ids.
  2. 列表开始
  3. 对于我们要过滤的每个(属性,值):
    1. product_ids = SELECT 'product_properties'.'product_id' FROM 'product_properties' WHERE 'product_properties'.'product_id' IN [list,of,product,ids] AND 'product_properties'.'property_id' = property_id AND 'product_properties'.'value' = 'some value here'
  4. 重复第 2 步,直到我们过滤完所有需要的属性。
  5. 最后,select 所有使用 SELECT * FROM 'products' WHERE 'products'.'id' IN [list,of,product,ids]
  6. 的匹配产品

此方法需要针对 N 个过滤器进行 N+1 次数据库查询。我希望可以将其合并到一个查询中。

我尝试了以下方法,但不起作用:

如何通过单个数据库查询(或尽可能少的查询)完成此操作?

我在 Rails 上使用 Ruby,这意味着我希望结果在 MySQL 和 SQLite 中都能工作。

谢谢!

这就是我尝试解决它的方法:

WITH FILTERS (property_id, filter_value) AS
(
          SELECT 1, 'foo'
UNION ALL SELECT 2, 'bar'
UNION ALL SELECT 3, 'baz'
)
SELECT prods.id
  FROM products prods
  JOIN product_properties props
    ON ( props.product_id = prods.id )
  JOIN filters f
    ON ( f.property_id = props.property_id AND f.filter_value = props.value )
 GROUP BY prods.id
HAVING COUNT(1) = ( SELECT COUNT(1) FROM filters )

这是它在做什么:

  • 首先,您提供过滤器列表作为 'WITH' 子句的一部分,以便它可以在同一个查询中。我假设在具有值 'foo'、'bar' 和 'baz'.
  • 的 3 个不同属性上添加 3 个过滤器
  • 其次,执行将过滤器与产品相匹配的查询。这就是 SELECTJOIN 正在做的事情。
  • 第三,对产品 ID 执行 GROUP BY,并对结果行执行 COUNT()。在 HAVING 子句中,检查产品计数是否与过滤器总数相同。如果是,那肯定是全部匹配了。

注意:您可以交替使用 UNION 方法,然后对结果执行 GROUP BYHAVING COUNT() 以查看其是否有效。只需确保对 ID 执行 UNION ALL 而不仅仅是 UNION.