如何过滤分组结果以匹配多个值?
how to filter Grouped results to match more than one value?
-问题本身可能没有很好地描述问题,但我不确定如何呈现它
我已经实现了this设计
,所以我有以下 table 图。
+---------------+ +-------------------+
| PRODUCTS |-----< PRODUCT_VARIANTS |
+---------------+ +-------------------+
| #product_id | | #product_id |
| product_name | | #variant_id |
+---------------+ | price |
| +-------------------+
| |
+--------^--------+ +--------^--------+
| PRODUCT_OPTIONS |-----< VARIANT_VALUES |
+-----------------+ +-----------------+
| #product_id | | #product_id |
| #option_id | | #variant_id |
+--------v--------+ | #option_id |
| | option_value_id|
+-----------------+ +--------v--------+
| OPTIONS | |
+-----------------+ |
| #option_id | |
| option_name | |
+-----------------+ |
| |
+-------^---------+ |
| OPTION_VALUES |-------------+
+-----------------+
| #option_id |
| #option_value_id|
| value_name |
+-----------------+
带有“#”的字段是主键
我想让用户使用 option_values
过滤产品。假设我有以下产品变体 shirtA(product) size(option) small(option_value), color(option) green(option_value)
,并且用户想要过滤所有具有 small and red
衬衫的产品,因此不应包括之前的产品变体。
我试过这样做
SELECT p.product_id, p.title, p.description FROM product_variants pv
JOIN products p ON pv.product_id = p .product_id
JOIN variant_values vv ON vv.product_variant_id = pv.product_variant_id
WHERE vv.option_value_id IN (6, 10)
GROUP BY (p.product_id, p.title, p.description);
但如您所见,它包括持有 option_value_id
6 或 10 而不是两者的产品,那么如何删除不具有两者的产品 option_values 而不是只有一个?
更新 1
澄清我需要做的是:强制所有选择的产品具有用户发送的所有选项值 ID(以数组的形式)WHERE vv.option_value_id IN (6, 10)
。这个想法就像在大多数电子商务网站中一样,当用户过滤 his/her 偏好 option_values
时,用户可能想要搜索 large (let's say that is option_value_id "6") and red (option_value_id "10") and maybe green...
等的所有产品。所以我不希望退回任何只有“红色”颜色但没有“大”尺寸的产品,如果用户在过滤器中添加了另一种颜色“绿色”,那么所有退回的产品都应该匹配所有三个过滤器(具有绿色和红色以及大尺寸)。
既然您已经有了一组预定义的 ID,也许您可以在这里使用一个数组。
SELECT p.product_id, p.title, p.description FROM product_variants pv
JOIN products p ON pv.product_id = p .product_id
JOIN variant_values vv ON vv.product_variant_id = pv.product_variant_id
WHERE vv.option_value_id IN (6, 10)
GROUP BY (p.product_id, p.title, p.description)
HAVING array_agg(distinct vv.option_value_id order by vv.option_value_id) = array[6,10];
您需要一个 having
子句。你的问题不清楚。但是如果你想要两者,那么使用:
SELECT p.product_id, p.title, p.description
FROM product_variants pv JOIN
products p
ON pv.product_id = p .product_id JOIN
variant_values vv
ON vv.product_variant_id = pv.product_variant_id
WHERE vv.option_value_id IN (6, 10)
GROUP BY p.product_id, p.title, p.description
HAVING COUNT(DISTINCT option_value_id) = 2;
如果只想要一个,可以将 2
更改为 1
。
如果动态 SQL 建筑适合您,您可以使用 INTERSECT 来过滤产品变体:
SELECT p.product_id, p.title, p.description
FROM product_variants pv
JOIN products p ON pv.product_id = p .product_id
JOIN (SELECT variant_id
FROM variant_values
WHERE (option_value_id = 6)
INTERSECT
SELECT variant_id
FROM variant_values
WHERE (option_value_id = 10)
) as vv ON vv.product_variant_id = pv.product_variant_id;
如果您计划大量产品变体及其选项,这可能不是最佳查询,但查询仍然足够简单,可以尝试。
-问题本身可能没有很好地描述问题,但我不确定如何呈现它
我已经实现了this设计 ,所以我有以下 table 图。
+---------------+ +-------------------+
| PRODUCTS |-----< PRODUCT_VARIANTS |
+---------------+ +-------------------+
| #product_id | | #product_id |
| product_name | | #variant_id |
+---------------+ | price |
| +-------------------+
| |
+--------^--------+ +--------^--------+
| PRODUCT_OPTIONS |-----< VARIANT_VALUES |
+-----------------+ +-----------------+
| #product_id | | #product_id |
| #option_id | | #variant_id |
+--------v--------+ | #option_id |
| | option_value_id|
+-----------------+ +--------v--------+
| OPTIONS | |
+-----------------+ |
| #option_id | |
| option_name | |
+-----------------+ |
| |
+-------^---------+ |
| OPTION_VALUES |-------------+
+-----------------+
| #option_id |
| #option_value_id|
| value_name |
+-----------------+
带有“#”的字段是主键
我想让用户使用 option_values
过滤产品。假设我有以下产品变体 shirtA(product) size(option) small(option_value), color(option) green(option_value)
,并且用户想要过滤所有具有 small and red
衬衫的产品,因此不应包括之前的产品变体。
我试过这样做
SELECT p.product_id, p.title, p.description FROM product_variants pv
JOIN products p ON pv.product_id = p .product_id
JOIN variant_values vv ON vv.product_variant_id = pv.product_variant_id
WHERE vv.option_value_id IN (6, 10)
GROUP BY (p.product_id, p.title, p.description);
但如您所见,它包括持有 option_value_id
6 或 10 而不是两者的产品,那么如何删除不具有两者的产品 option_values 而不是只有一个?
更新 1
澄清我需要做的是:强制所有选择的产品具有用户发送的所有选项值 ID(以数组的形式)WHERE vv.option_value_id IN (6, 10)
。这个想法就像在大多数电子商务网站中一样,当用户过滤 his/her 偏好 option_values
时,用户可能想要搜索 large (let's say that is option_value_id "6") and red (option_value_id "10") and maybe green...
等的所有产品。所以我不希望退回任何只有“红色”颜色但没有“大”尺寸的产品,如果用户在过滤器中添加了另一种颜色“绿色”,那么所有退回的产品都应该匹配所有三个过滤器(具有绿色和红色以及大尺寸)。
既然您已经有了一组预定义的 ID,也许您可以在这里使用一个数组。
SELECT p.product_id, p.title, p.description FROM product_variants pv
JOIN products p ON pv.product_id = p .product_id
JOIN variant_values vv ON vv.product_variant_id = pv.product_variant_id
WHERE vv.option_value_id IN (6, 10)
GROUP BY (p.product_id, p.title, p.description)
HAVING array_agg(distinct vv.option_value_id order by vv.option_value_id) = array[6,10];
您需要一个 having
子句。你的问题不清楚。但是如果你想要两者,那么使用:
SELECT p.product_id, p.title, p.description
FROM product_variants pv JOIN
products p
ON pv.product_id = p .product_id JOIN
variant_values vv
ON vv.product_variant_id = pv.product_variant_id
WHERE vv.option_value_id IN (6, 10)
GROUP BY p.product_id, p.title, p.description
HAVING COUNT(DISTINCT option_value_id) = 2;
如果只想要一个,可以将 2
更改为 1
。
如果动态 SQL 建筑适合您,您可以使用 INTERSECT 来过滤产品变体:
SELECT p.product_id, p.title, p.description
FROM product_variants pv
JOIN products p ON pv.product_id = p .product_id
JOIN (SELECT variant_id
FROM variant_values
WHERE (option_value_id = 6)
INTERSECT
SELECT variant_id
FROM variant_values
WHERE (option_value_id = 10)
) as vv ON vv.product_variant_id = pv.product_variant_id;
如果您计划大量产品变体及其选项,这可能不是最佳查询,但查询仍然足够简单,可以尝试。