如何 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...
。
我有一个 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...
。