【问题标题】:MSSQL Permutations/Combinations - Finding all possible matches using data subsetMSSQL 排列/组合 - 使用数据子集查找所有可能的匹配项
【发布时间】:2018-12-21 17:22:18
【问题描述】:

在 MSSQL 中,我有一个表 (ProductRecipe),其中包含多达 5 个不同的组件产品。然后,我有一个数据集,其中包含各个组件产品及其成本。

我想做的是找到所有能满足我食谱的不同排列/组合。

CREATE TABLE #ProductRecipe (ProductRecipeID INT, Component1 INT, Component2 INT, Component3 INT, Component4 INT, Component5 INT)
CREATE TABLE #ComponentPricing (RowID INT, PricingID INT, ProductID INT, ProductDescription VARCHAR(50), Cost DECIMAL(18,6))

INSERT INTO #ProductRecipe (ProductRecipeID, Component1, Component2) VALUES (21, 130, 468)
INSERT INTO #ComponentPricing (RowID, PricingID, ProductID, ProductDescription, Cost)
VALUES (1, 314023, 130, 'ULS2', 1.783800)
 , (2, 313616, 130, 'ULS2', 1.783800)
 , (3, 313071, 130, 'ULS2', 1.794000)
 , (4, 312865, 130, 'ULS2', 1.789500)
 , (5, 316323, 468, 'B100', 1.550500)

SELECT * FROM #ProductRecipe
SELECT * FROM #ComponentPricing

DROP TABLE #ProductRecipe
DROP TABLE #ComponentPricing

我试图达到的结果是我最终得到了 4 种不同的配方变体,因为前 4 条记录(用于 ProductID 130)可以与最后一条记录(ProductID 468)混合。只有这两种产品可以混合,因为它们是我的 ProductRecipe 表中定义的两种成分产品。

期望的结果: 1+5排一起走,2+5排一起走,3+5排一起走,4+5排一起走;返回 PricingID 列。

ProductRecipeID Component1 Component2 Component3 Component4 Component5
21              314023     316323   
21              313616     316323   
21              313071     316323   
21              312865     316323   

【问题讨论】:

  • 具体的数据库引擎是什么? PostgreSQL、Oracle、DB2 等。该解决方案很可能是特定于数据库的。
  • 这是 MSSQL 2012
  • 为什么要裁员?配方 ID 和配方在成分表中的成分编号,还有配方中的成分产品 ID 和隐含的成分编号。那么为什么有五列用于组件,而不仅仅是一个列出每个配方的组件的表格?我建议你修改那个设计。
  • 好点。在我被卡住的时候,这是我拥有的数据。从技术上讲,存在冗余的原因是因为我过滤了更大的数据子集,只包括我的食谱中存在的产品。我将更新示例代码以使其更加清晰。谢谢!

标签: sql combinations permutation


【解决方案1】:

看看这是否有效。

DECLARE @ProductRecipe TABLE (ProductRecipeID INT, Component1 INT, Component2 INT, Component3 INT, Component4 INT, Component5 INT) 
DECLARE @ComponentPricing TABLE (RowID INT, PricingID INT, ProductID INT, ProductDescription VARCHAR(50), Cost DECIMAL(18,6)) 

INSERT INTO @ProductRecipe (ProductRecipeID, Component1, Component2,Component3) VALUES (21, 130, 468,221)
INSERT INTO @ComponentPricing (RowID, PricingID, ProductID, ProductDescription, Cost)
VALUES (1, 314023, 130, 'ULS2', 1.783800)
 , (2, 313616, 130, 'ULS2', 1.783800)
 , (3, 313071, 130, 'ULS2', 1.794000)
 , (4, 312865, 130, 'ULS2', 1.789500)
 , (5, 316323, 468, 'B100', 1.550500)
 , (6, 316322, 221, 'B1110', 1.5250500)

;WITH UnpivotedRecipe AS
(
    SELECT 
        ProductRecipeID, ComponentID
    FROM
        (SELECT * FROM @ProductRecipe) AS P
        UNPIVOT(ComponentID FOR V IN(Component1,Component2,Component3,Component4,Component5))AS UP
)
, JoinedData AS
(
    SELECT 
        ProductRecipeID, ComponentID, RowID
    FROM 
        UnpivotedRecipe R
        INNER JOIN @ComponentPricing C ON C.ProductID = R.ComponentID

)
SELECT DISTINCT J1.ComponentID,J1.RowID,J2.ComponentID FROM JoinedData J1
CROSS JOIN JoinedData J2
WHERE
    J1.ComponentID<>J2.ComponentID

【讨论】:

  • 这太棒了!非常感谢。我现在唯一想弄清楚的是如何停止重复的组合。我没有在我的原始帖子中指定该要求。基本上,我得到了两次组合;只是相反的顺序。
  • 另外,我相信最后的 WHERE 子句,我们需要 J1.ProductRecipe = J2.ProductRecipe;没有它,如果定义了多个配方,则会失败。
  • 是的,我明白了。需要对最终结果进行左连接,其中 ROW_NUMBER() 的可能派生字段由左连接的 ProductReciept 在 case 语句中进行分区,以使 NULLS = 1,并且可能是派生字段 = 1 的最终过滤器。我稍后会尝试,看看它是否会起作用。如果没有,那么这是我能及时得到的最接近的时间:(
【解决方案2】:

在自联接表上考虑多个LEFT JOIN

SELECT p.ProductRecipeID, c1.PricingID AS Component1, c2.PricingID AS Component2,
       c3.PricingID AS Component3, c4.PricingID AS Component4
FROM #ProductRecipe p
LEFT JOIN #ComponentPricing c1
    ON p.Component1 = c1.ProductID   
LEFT JOIN #ComponentPricing c2
    ON p.Component2 = c2.ProductID
LEFT JOIN #ComponentPricing c3
    ON p.Component3 = c3.ProductID
LEFT JOIN #ComponentPricing c4
    ON p.Component4 = c4.ProductID

Rextester Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多