通过多个(一组)多对多变体过滤产品

问题描述 投票:0回答:1

任何人都可以帮我通过 SQL Server 中的一组多对多变体来过滤产品表吗?按单个变体进行过滤很简单,但我无法理解多个变体。

我在这里设置了一个sql fiddle: https://sqlfiddle.com/sql-server/online-compiler?id=489fb6f3-1b8e-4256-88be-11a4c900e900

PRODUCTS
+--------------+
| Id | Name    |
+----+---------+
| 1  | Bike 1  |
| 2  | Bike 1  |
+----+---------+

Variations
+-----------------+
| Id | Name       |
+----+------------+
| 1  | Style      |
| 2  | Colour     |
| 3  | Wheel Size |
+----+------------+

VariationValues
+------------------+-----------+
| Id | VariationId | ValueName |
+----+-------------+-----------+
| 1  |  1          | MTB       |
| 2  |  1          | Tourer    |
| 3  |  1          | Racer     |
| 4  |  2          | Red       |
| 5  |  2          | Blue      |
| 6  |  2          | Black     |
| 7  |  3          | 26 inch   |
| 8  |  3          | 29 inch   |
+----+-------------+-----------+

ProductVariations
+-----------------+------------------+
| Id  | ProductId | VariationValueId |
+-----+-----------+------------------+
| 1   |  Bike 1   | 1 (MTB)          |
| 2   |  Bike 1   | 5 (Blue)         |
| 3   |  Bike 1   | 7 (26 inch)      |
| 4   |  Bike 2   | 2 (Tourer)       |
| 5   |  Bike 2   | 4 (Red)          |
| 6   |  Bike 2   | 7 (26 inch)      |
| 7   |  Bike 3   | 3 (Racer)        |
| 9   |  Bike 3   | 2 (Black)        |
| 10  |  Bike 3   | 8 (29 inch)      |
| 11  |  Bike 4   | 1 (MTB)          |
| 12  |  Bike 4   | 2 (Black)        |
| 13  |  Bike 4   | 7 (26 inch)      |
+-----+-----------+------------------+

-- This query gets the bikes that match this style
DECLARE @Style int = 1; -- MTB (should find Bike 1 and Bike 4, which it does)

SELECT p.Name, vv.ValueName --,vv.Id as ValueId, pv.VariationValueId
FROM Products p 
inner join ProductVariations pv on pv.ProductId=p.Id
inner join VariationValues vv on vv.Id = pv.VariationValueId
where 
pv.VariationValueId=@Style
order by p.Name



--But the problem is, how to select products that match  multiple variations?
     -- This will NOT work
    DECLARE @Style int = 1; -- MTB
        DECLARE @Colour int = 5; -- BLUE
        DECLARE @WheelSize int =7; -- 26 inch
        
        SELECT p.Name, vv.ValueName --,vv.Id as ValueId, pv.VariationValueId
        FROM Products p 
        inner join ProductVariations pv on pv.ProductId=p.Id
        inner join VariationValues vv on vv.Id = pv.VariationValueId
        where 
        pv.VariationValueId=@Style 
    and pv.VariationValueId=@Colour
    and pv.VariationValueId=@WheelSize
        order by p.Name

感谢您的帮助

sql sql-server filter many-to-many
1个回答
0
投票

聚合是解决此问题的一种规范方法。 假设您只想匹配产品名称,您可以使用:

SELECT p.Name
FROM Products p
INNER JOIN ProductVariations pv
    ON pv.ProductId = p.Id
INNER JOIN VariationValues vv
    ON vv.Id = pv.VariationValueId
WHERE pv.VariationValueId IN (@Style, @Colour, @WheelSize)
GROUP BY p.Name
HAVING COUNT(DISTINCT pv.VariationValueId) = 3
ORDER BY p.Name;

这里的想法是按产品名称聚合,限制为仅具有您想要的三个变体值的记录,然后断言每个匹配产品都存在所有 3 个变体。

如果您还想选择 other 列,请将以上内容放入 CTE 中,并仅根据匹配产品进行过滤:

WITH cte AS (
    SELECT p.Name
    FROM Products p
    INNER JOIN ProductVariations pv ON pv.ProductId = p.Id
    INNER JOIN VariationValues vv ON vv.Id = pv.VariationValueId
    WHERE pv.VariationValueId IN (@Style, @Colour, @WheelSize)
    GROUP BY p.Name
    HAVING COUNT(DISTINCT pv.VariationValueId) = 3
)

SELECT p.Name, vv.ValueName, vv.Id AS ValueId, pv.VariationValueId
FROM Products p
INNER JOIN ProductVariations pv
    ON pv.ProductId = p.Id
INNER JOIN VariationValues vv
    ON vv.Id = pv.VariationValueId
WHERE p.Name IN (SELECT Name FROM cte);
© www.soinside.com 2019 - 2024. All rights reserved.