如何 select 匹配多个条件的不同列值

How to select a distinct column value matching multiple criterea

我有一个 table 包含具有以下结构的属性:

id: bigint unsigned autoincrement
product_id: bigint foreign key 
attribute_id: bigint foreign key
value:  varchar(100) 

我可以按以下方式查询一个条件:

SELECT DISTINCT product_id FROM product_attributes WHERE attribute_id = ? AND value = ?

但是我需要能够找到符合多个此类条件的产品,并且出于性能原因希望避免多个数据库查询。简单地用 AND 添加更多条件是行不通的,因为它们将涉及相同的列,例如:

SELECT DISTINCT product_id FROM product_attributes WHERE attribute_id = 1 AND value = 'Blue'
INTERSECT
SELECT DISTINCT product_id FROM product_attributes WHERE attribute_id = 2 AND value = '36'
INTERSECT
SELECT DISTINCT product_id FROM product_attributes WHERE attribute_id = 3 AND value = 'slim'

我读过 INTERSECT 语句,它似乎可以工作,但我读到 MySQL 不支持它,搜索 MySQL 8 文档没有产生相关结果,并且我认为上面的查询是正确的,在 MySQL.

上产生错误

我还读到过类似的事情可以通过内部联接实现,但我发现的所有示例都涉及多个 table。可能还有更好或更简单的方法来编写我没有想到的查询。或者实际上发送多个查询并计算 MySQL 之外的交集实际上更好(尽管我会感到非常惊讶)我非常感谢过去做过类似事情的任何人的帮助。

您需要使用聚合来统计条件集匹配的行数,并断言等于条件数:

SELECT product_id
FROM product_attributes
WHERE (attribute_id, value) IN ((1, 'Blue'), (2, '36'), (3, 'slim'))
GROUP BY product_id
HAVING COUNT(*) = 3

这是键/值存储问题。

为所欲为,就是脖子有点痛。使用 JOIN 操作将值转换为一行。像这样。

    SELECT p.product_id, 
           color.value AS color,
           size.value AS size,
           cut.value AS cut
      FROM ( SELECT DISTINCT product_id FROM product_attributes ) p
      LEFT JOIN product_attributes color ON color.product_id = p.product_id 
                                        AND color.attribute_id = 1
      LEFT JOIN product_attributes size  ON size.product_id = p.product_id 
                                        AND size.attribute_id = 2
      LEFT JOIN product_attributes cut   ON cut.product_id = p.product_id 
                                        AND cut.attribute_id = 3

这会生成每个 product/color/size/cut 组合一行的结果集

然后你可以像这样过滤那个结果集

SELECT * 
  FROM (
      SELECT p.product_id, 
             color.value AS color,
             size.value AS size,
             cut.value AS cut
        FROM ( SELECT DISTINCT product_id FROM product_attributes ) p
        LEFT JOIN product_attributes color ON color.product_id = p.product_id 
                                          AND color.attribute_id = 1
        LEFT JOIN product_attributes size  ON size.product_id = p.product_id 
                                          AND size.attribute_id = 2
        LEFT JOIN product_attributes cut   ON cut.product_id = p.product_id 
                                          AND cut.attribute_id = 3
       ) combinations
 WHERE color='Blue' AND size='36' AND cut='slim'

MySQL 的查询规划器足够聪明,在给定适当索引的情况下,运行 不会像您猜测的那样慢。

FROM 子句生成一个完整的产品 ID 列表,从您的 product_attributes table 加入特定属性。如果您有其他 table 产品,请使用它代替 SELECT DISTINCT...