Reputation: 1121
I need to split an invoice line into (in this instance) 3 parts (each with 2 decimal places), but I have ensure that the sum of the splits adds up to the original value.
For example: if I split 5.13 by 3%, 42% and 55% (each rounded to 2DP) I end up with:
0.15
2.82
2.15
Sum = 5.12.
The only way I can figure out how to do it is to use a case statement and split to 2DP on all but the last row.
For the last row, sum all the previous values and subtract this from the original value. This approach requires a few sub-selects. I'm sure there's a better way to do it, but drawing a blank.
(FYI, it's a 3rd party vendor product, so I have to start with a MONEY and return a insert into a MONEY type column and all values must be 2DP
Here's my example:
DECLARE
@CurrExtPrice money = 5.13
DECLARE @tGLSplit AS TABLE
(
ID INT IDENTITY(1,1)
,GLCode NVARCHAR(50)
,PercentSplit DECIMAL(18, 2)
)
INSERT INTO @tGLSplit
([GLCode], [PercentSplit])
Select
'Split1', 0.03
UNION ALL
Select
'Split2', 0.55
UNION ALL
Select
'Split3', 0.42
-- Source Date
SELECT * FROM @tGLSplit [tgs]
SELECT
@CurrExtPrice AS OriginalValue
,tg.[PercentSplit]
,CAST(@CurrExtPrice * tg.[PercentSplit] AS DECIMAL(18,2)) AS Split2DP
,CASE
WHEN tg.ID < (SELECT MAX(ID) FROM @tGLSplit)
THEN
CAST(@CurrExtPrice * tg.[PercentSplit] AS DECIMAL(18,2))
ELSE
(SELECT @CurrExtPrice - SUM(CAST(@CurrExtPrice * [PercentSplit] AS decimal(18,2))) FROM @tGLSplit WHERE ID < (SELECT MAX(ID) FROM @tGLSplit) )
END AS NewSplitValue
FROM @tGLSplit tg
Anyone have a magic algorithm?
TIA
Mark
Upvotes: 3
Views: 1853
Reputation: 1431
This was successful for me. Rounding to the 1000's at a line level seemed to produce a sum that worked when rounded to the 100's. Cleanup and modify to your specific needs.
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp
GO
DECLARE @Total MONEY = 5.13;
;WITH
SplitData AS
(
SELECT .03 AS SplitPercent
UNION
SELECT .42
UNION
SELECT .55 AS SplitPercent
),
Percents AS
(
SELECT S.SplitPercent,
@Total AS FullMoneyValue,
@Total * S.SplitPercent AS Total,
ROUND(@Total * S.SplitPercent,3,0) AS RoundedTotal
FROM SplitData AS S
)
SELECT P.*
INTO #Temp
FROM Percents AS P
SELECT SUM(P.Total), ROUND(SUM(P.RoundedTotal),2,0)
FROM #Temp AS P
Upvotes: 1