Search code examples
sqlt-sqlconcatenationskus

Get all possible concatenations


I have a database that I've inherited and need to create a query that generates all possible variations of a SKU. One table has the "base" SKU and the other table has all the SKU modifiers.

Example

Base SKU: MARIN could be modified into

MARINR15 MARINB15 MARING15 MARINR17 MARINB17 MARING17 MARINR19 MARINB19 MARING19 MARINR20 MARINB20 MARING20

Base SKU

ProductID   SKU
----------- ---------------
532         MARIN

SKU Modifiers

ProductID   OptionName           OptionValue              SkuModifier
----------- -------------------- ------------------------ -----------
532         Color                Red                      R
532         Color                Green                    G
532         Color                Blue                     B
532         Size                 17"                      17
532         Size                 15"                      15
532         Size                 19"                      19
532         Size                 20"                      20

Solution

  • You can use a recursive solution (and indeed, this is probably the only viable answer). You'd probably save processing if you had a predifined ordering (because at the moment the only way I can think to do this is text concatenation).

    Here is a general solution that should get you your needed results.
    Note that this was written and run on DB2 (iSeries) - you may need to adjust it for SQL Server.

    WITH Combined(productId, options, combination, level) as (
                  SELECT productId, optionName, skuModifier, 1
                  FROM #Modifiers
                  UNION ALL
                  SELECT a.productId, a.options || b.optionName,
                         a.combination || b.skuModifier, a.level + 1
                  FROM Combined as a
                  JOIN #Modifiers as b
                  ON b.productId = a.productId
                  AND a.options not like ('%' || b.optionName || '%')),
         Option_Count(productId, count) as (SELECT productId, COUNT(DISTINCT optionName)
                                            FROM #Modifiers
                                            GROUP BY productId)
    SELECT a.sku || COALESCE(b.combination, '')
    FROM #Base as a
    LEFT JOIN (Combined as b
               JOIN Option_Count as c
               ON c.productId = b.productId
               AND c.count = b.level)
    ON b.productId = a.productId)
    

    Which yields:

    MARIN17R        
    MARIN15R        
    MARIN19R        
    MARIN20R        
    MARIN17G        
    MARIN15G        
    MARIN19G        
    MARIN20G        
    MARIN17B        
    MARIN15B        
    MARIN19B        
    MARIN20B        
    MARINR17        
    MARING17        
    MARINB17        
    MARINR15        
    MARING15        
    MARINB15        
    MARINR19        
    MARING19   
    MARINB19   
    MARINR20   
    MARING20   
    MARINB20
    

    Personally, though, I think I'd try to get some sort of ordering established - this would at least allow you to knock out dealing with optionName (although in that case you may want to further normalize the tables).
    Please note that the CTE Option_Count is being used to restrict results to 'full-length' combinations - permutations where all the options are used, rather than just some of them.