计算产品过滤器中每个项目的产品

时间:2019-01-15 19:57:31

标签: php mysql filtering

我需要帮助编写SQL(或逻辑过程)以对产品过滤器中每个产品的产品进行计数。

数据库结构:

products
--------
id|title


attributes
----------
id|title


attributes_values
---------------------
id|value|attribute_id


products_attributes
-------------------
product_id|attributes_value_id

我有带有属性的侧边栏过滤器,我需要获取每个属性的产品计数(行过滤器)。问题在于计数应该已经受到已经选择的属性的限制。因此,当我选择任何属性时,所有其他属性也都必须计算具有所选属性的产品。

例如:我有两个属性,颜色(蓝色,白色)和材料(金属,木材)。选择蓝色后,我需要计算蓝色的金属和蓝色的木材的产品计数-计数的产品必须与所有选定的属性匹配。

可以使用任何联接表或外部服务,但我不知道该怎么做,如何更改结构以使其工作。

DBFiddle:https://www.db-fiddle.com/f/mMeUzm96xb9ZMHZonEktcD/1

感谢任何想法。

1 个答案:

答案 0 :(得分:0)

那么第一步就是将这些表attributesattributes_valuesproducts_attributes组合成诸如product_metaproduct_options甚至是{{1} }。

每个产品与属性之间只有一对多的关系。例如,一个产品可以具有许多属性,但是一个属性仅属于一个产品。请注意,这仍然允许您具有重复的属性。例如,没有理由产品1不能具有2种颜色属性。

为确保可以将其“规范化”到您拥有的级别,但这是不必要的,并且只会使SQL复杂化,并在以后引起各种麻烦。那么而不是什么呢? 2多对多关系和一对多关系,您真正需要的就是一对多

所以我们将从这里开始:

product_attributes

现在开始查询

products
--------
id|title

product_attributes
id|product_id|attr_key|attr_value

这将为您提供所有蓝色产品的数量(与材料无关)。向前挺遥遥,但并非我们真正需要的。

添加材料要困难一些,但是可以通过再次加入属性(以及对值进行分组等)来完成,就像这样:

SELECT 
   COUNT(p.id)
FROM
   products p
JOIN
   product_attributes pa ON p.id = pa.product_id
WHERE
   (pa.attr_key="color" AND pa.attr_value="blue")

基本上,我们正在选择所有具有“颜色”蓝色属性和“材料” {something}属性的产品。

当您使用这样的键值存储并想要访问同一张表中的两个值时,这将需要在表上进行额外的联接。因此,如果您有一个非常复杂的架构,仅具有3个表用于这些属性,则必须多次重现所有这些辅助联接。最好保持简单。

也请参阅此数据库小提琴

https://www.db-fiddle.com/f/mdVypFwY7WsfHcgkasR7gE/1

  SELECT 
     COUNT(p.id)
  FROM
     products p
  JOIN
     #instead of one table, with your schema you would need 3 (apx) joins here
     product_attributes pa ON p.id = pa.product_id
  JOIN
     #you would also need 3 joins here
     product_attributes pa1 ON p.id = pa1.product_id 
  WHERE
     pa.attr_key="color" AND pa.attr_value="blue"
     AND 
     pa1.attr_key="material"

上述查询的结果是CREATE TABLE products( id INT(10), title VARCHAR(250) ); INSERT INTO products (id,title)VALUES(1,'foo'); INSERT INTO products (id,title)VALUES(2,'bar'); CREATE TABLE product_attributes( id INT(10), product_id INT(10), attr_key VARCHAR(250), attr_value VARCHAR(250) ); INSERT INTO product_attributes (id,product_id,attr_key,attr_value)VALUES(1,1,'color', 'blue'); INSERT INTO product_attributes (id,product_id,attr_key,attr_value)VALUES(2,1,'color', 'white'); INSERT INTO product_attributes (id,product_id,attr_key,attr_value)VALUES(3,1,'material', 'metal'); INSERT INTO product_attributes (id,product_id,attr_key,attr_value)VALUES(4,1,'material', 'wood'); #say we also have plastic INSERT INTO product_attributes (id,product_id,attr_key,attr_value)VALUES(4,1,'material', 'plastic'); INSERT INTO product_attributes (id,product_id,attr_key,attr_value)VALUES(1,2,'color', 'white'); 1(请注意,我添加了第3个材料),只有2个您得到了正确的计数。这表明您只能拥有2个。如果您想将其限制为3个中的2个,请执行以下操作:

3

您可以选择不带attr值来对此进行一点验证,这将得到 WHERE pa.attr_key="color" AND pa.attr_value="blue" AND pa1.attr_key="material" AND pa1.attr_value IN("wood", "metal") ,分别为6metal/bluemetal/whitewood/blue和(在我的示例中)wood/whiteplastic/blue。这些属性的所有可能组合都是这样。

最后一点是您可以在plastic/whiteattr_key上放置一个唯一索引作为复合键,这样可以防止重复的键/值对。