我有以下数据库结构来存储产品选项。
现在我有问题来筛选出只匹配给定选项的产品。首先我做了WHERE option_id IN(选项数组),但这会给我产品匹配任何选项,而不是解决方案。例如,用户只想过滤掉具有给定材料,颜色和尺寸的产品。如果我做WHERE option_id = 4 AND option_id = 6,例如我什么都没得到。
这是我的问题:
SELECT DISTINCT p.id AS id,
...
FROM products p
LEFT JOIN product_categories pc ON p.id = pc.product_id
LEFT JOIN product_images pi ON p.id = pi.product_id
LEFT JOIN product_options po ON p.id = po.product_id
WHERE p.product_active = 1
AND po.option_id = 1 // only to get the idea
GROUP BY id
ORDER BY id DESC
LIMIT 0,
12
只是提到它是PHP应用程序,用户从select元素中选择带有或不带多个属性的选项。
如何实现这个目标?
答案 0 :(得分:4)
您可以使用having
:
SELECT p.id AS id, ...
FROM products p JOIN
product_categories pc
ON p.id = pc.product_id LEFT JOIN
product_images pi
ON p.id = pi.product_id JOIN
product_options po
ON p.id = po.product_id
WHERE p.product_active = 1 AND
po.option_id IN (4, 6)
GROUP BY p.id
HAVING COUNT(DISTINCT po.option_id) = 2
ORDER BY p.id DESC
LIMIT 0, 12;
HAVING
子句指定给定的id
有两个匹配选项。由于WHERE
子句,这些是您唯一关心的两个选项。
我没有改变你的方法(你没有提供完整的查询),但你正在进行不同维度的连接 - 类别,图像和选项。这为每个产品创建了一个笛卡尔积,这通常不是这种查询的最佳方法。
答案 1 :(得分:1)
解决方案中无需LEFT JOIN
。
SELECT DISTINCT p.id AS id
FROM products p
JOIN product_options po ON p.id = po.product_id
WHERE p.product_active = 1
AND po.option_id IN (1, 2, 3)
GROUP BY p.id
HAVING COUNT(po.option_id) = 3
我的解决方案只保留查找具有指定选项的产品所需的表格。
如果您希望产品具有恰好此选项而没有其他产品,则可以使用NOT EXISTS
:
SELECT DISTINCT p.id AS id
FROM products p
JOIN product_options po ON p.id = po.product_id
WHERE p.product_active = 1 AND
po.option_id IN (1, 2, 3) and
NOT EXISTS (
SELECT 1
FROM product_options po2
WHERE p.id = po2.product_id and po2.option_id NOT IN (1, 2, 3)
)
GROUP BY p.id
HAVING COUNT(po.option_id) = 3
如果您想选择符合其他条件的产品(如产品类别等),请在IN
子句中使用WHERE
。此方法可避免生成重复po.option_id
,即使DISTINCT
中没有COUNT
,外部查询仍可正常工作。
SELECT DISTINCT p.id AS id
FROM products p
JOIN product_options po ON p.id = po.product_id
WHERE p.product_active = 1 AND
po.option_id IN (1, 2, 3) AND
-- use the following IN predicate to select products with specific features without introducing duplicates in your query
p.id IN (
select product_id FROM product_categories WHERE <your_condition>
)
GROUP BY p.id
HAVING COUNT(po.option_id) = 3
答案 2 :(得分:0)
您选择带有图像列表的产品。类似的东西:
select products.*, group_concat(product_images.id)
此外,产品必须满足各种选择。这是属于WHERE
子句的标准。
select
p.*,
(select group_concat(image) from product_images i where i.product_id = p.id) as images
from products p
where product_active = 1
and id in
(
select product_id
from product_options
where option_id in (1,3,55,97)
group by product_id
having count(*) = 4 -- four options in this example
);
答案 3 :(得分:0)
谢谢你们,我已经成功归还了我想要的东西。
现在我对过滤产品的分页查询存在问题。
最终搜索查询:
SELECT DISTINCT p.id AS id,
main_price,
promotion_price,
NEW,
sale,
recommended,
COUNT(pi.filename) AS image_count,
GROUP_CONCAT(DISTINCT pi.filename
ORDER BY pi.main_image DESC, pi.id ASC) AS images,
name_sr,
uri_sr,
description_sr
FROM products p
LEFT JOIN product_categories pc ON p.id = pc.product_id
LEFT JOIN product_images pi ON p.id = pi.product_id
LEFT JOIN product_options po ON p.id = po.product_id
WHERE p.product_active = 1
AND po.option_id IN(1)
AND p.main_price BETWEEN 5250.00 AND 14000.00
GROUP BY id
HAVING COUNT(DISTINCT po.option_id) = 1
ORDER BY id DESC
LIMIT 0,
12
分页查询是这样的,我根据新的过滤查询修改了它:
SELECT COUNT(DISTINCT p.id) AS number
FROM products p
LEFT JOIN product_categories pc ON p.id = pc.product_id
LEFT JOIN product_images pi ON p.id = pi.product_id
LEFT JOIN product_options po ON p.id = po.product_id
WHERE p.product_active = 1
AND po.option_id IN(1)
AND p.main_price BETWEEN 5250.00 AND 14000.00
GROUP BY(p.id)
HAVING COUNT(DISTINCT po.option_id) = 1
如果我在SELECT COUNT中省略了DISTINCT,我没有得到过滤分页,如果我设置了DISTINCT,我会得到对应于分页的行数。我想我可以使用子查询为所有这些添加另一个计数(*),但不确定是否可行,以及是否有更有效和更优雅的方法来执行此操作。