I have some SQL written up to address my problem but it is not quite ready. I have been attempting different queries for days now without much luck. FYI I inherited this DB so it may be a bit more advanced than what I am used to.
There is a many-to-many relationship between Formula and Color using the bridge table FormulaColor. FormulaColor has the columns (FormulaId, ColorId, Percentage).
My Business problem, we are converting all the formulas that use color A with the colors B(1%), C(2.8%) and D(96.2%). So if a Formula currently uses the color A as 50% of the formula then I would add a row for that formula with the B color and a percentage of .5%, a row for C color with a percentage of 1.4% and a row for D color with a percentage of 48.1%.
The problem though, is a given formula that contains color A, may also already contain one or more of colors B, C or D. In that case I need to update the percentage by simply adding what was calculated above.
The actual sql that I have so far is as follows. *Note that this is just for handling 1 of the new colors (ColorId=2594)
INSERT INTO FormulaColor (FormulaId, ColorId, Percentage)
SELECT FormulaId, 2594 as ColorId, round((.01*FormulaColor.Percentage),2) as Percentage
FROM FormulaColor WHERE ColorId=2595;
DELETE FROM FormulaColor WHERE ColorId = 2595;
I was thinking that using the upsert method that uses @@rowscount is what I need? If so, I can’t figure out how to do the update to just add the calculated amount to the percentage.
Any help or resources is appreciated!
UPDATE
I ended up using the solution from Andriy M. In case it helps someone else out I am posting the actual SQL that I used.
DECLARE @DeletedColor int;
DECLARE @Replacement TABLE (ColorId int, Percentage float);
-- old ColorId getting replaced
SET @DeletedColor = 2595
-- new ColorId's and the percentages needed to recalculate
INSERT INTO @Replacement (ColorId, Percentage) VALUES (2594, .01)
INSERT INTO @Replacement (ColorId, Percentage) VALUES (2521, .028)
INSERT INTO @Replacement (ColorId, Percentage) VALUES (2533, .962)
SELECT
fc.FormulaId,
r.ColorId,
Percentage = round(fc.Percentage * r.Percentage, 2)
INTO #FormulaColor
FROM FormulaColor fc
CROSS JOIN @Replacement r
WHERE fc.ColorId = @DeletedColor
;
UPDATE old
SET old.Percentage = old.Percentage + new.Percentage
FROM FormulaColor old
INNER JOIN #FormulaColor new
ON old.FormulaId = new.FormulaId
AND old.ColorId = new.ColorId
;
INSERT INTO FormulaColor (FormulaId, ColorId, Percentage)
SELECT new.FormulaId, new.ColorId, new.Percentage
FROM #FormulaColor new
LEFT JOIN FormulaColor old
ON old.FormulaId = new.FormulaId
AND old.ColorId = new.ColorId
WHERE old.FormulaId IS NULL
;
DELETE FROM FormulaColor WHERE ColorId = @DeletedColor;
Let
@DeletedColorbe the ID of the colour to delete, and@Replacementthe table of the replacement colours, declared like this:One way to approach the problem would be like this:
Prepare the actual colour values to add to every formula:
This is creating a list of replacement colours for every formula containing the
@DeletedColor. The percentage specified for every replacement colour in the replacement table is factored by the percentage of each formula’s@DeletedColorto form the final percentage for the replacement colour.Update existing
FormulaColorcolours from the just created row set:Insert the colours from the new row set to the formulas that do not contain those colours:
Naturally, since you are modifying the actual table using more than one statement, it would be best to carry out the modifications in a transaction to ensure their atomicity.