Get all possible concatenations
-
18-02-2021 - |
Question
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.
OTHER TIPS
DROP TABLE #Base
DROP TABLE #Modifiers
CREATE TABLE #Base
(
ProductId int,
SKU varchar(32)
)
CREATE TABLE #Modifiers
(
ProductId int,
OptionName varchar(32),
OptionValue varchar(32),
SKUModifier varchar(32)
)
INSERT INTO #Base
SELECT 532, 'MARIN'
INSERT INTO #Modifiers
SELECT 532, 'Color', 'Red', 'R' UNION ALL
SELECT 532, 'Color', 'Green', 'G' UNION ALL
SELECT 532, 'Color', 'Blue', 'B' UNION ALL
SELECT 532, 'Size', '17"', '17' UNION ALL
SELECT 532, 'Size', '15"', '15' UNION ALL
SELECT 532, 'Size', '19"', '19' UNION ALL
SELECT 532, 'Size', '20"', '20'
SELECT B.SKU + M.SKUModifier + M2.SKUModifier FROM #Base B
JOIN #Modifiers M ON B.ProductId = M.ProductId AND M.OptionName = 'Color'
JOIN #Modifiers M2 ON B.ProductId = M2.ProductId AND M2.OptionName = 'Size'
Results:
MARINR17
MARING17
MARINB17
MARINR15
MARING15
MARINB15
MARINR19
MARING19
MARINB19
MARINR20
MARING20
MARINB20
SELECT
base.sku+color.SkuModifier+size.SkuModifier
FROM base
INNER JOIN modifiers as color ON color.OptionName = 'Color'
INNER JOIN modifiers as size ON size.OptionName = 'Size'
You'll probably have to process OptionValue (for instance, removing the " from Size and taking the first letter from Color), but this will get you on the right path.
EDIT -- Thanks for the clarification, I've updated the SQL.