SQL - 除以一个值并确保它重新求和到原始值
SQL - Divide a value and make sure it re-sums to original
我需要将发票行拆分为(在本例中)3 个部分(每个部分有 2 位小数),但我已确保拆分的总和等于原始值。
例如:如果我将 5.13 分成 3%、42% 和 55%(分别四舍五入为 2DP),我最终得到:
0.15
2.82
2.15
Sum = 5.12.
我能弄清楚如何做到这一点的唯一方法是使用 case 语句并在除最后一行以外的所有行上拆分为 2DP。
对于最后一行,将所有先前值相加并从原始值中减去。这种方法需要一些子选择。我敢肯定有更好的方法可以做到这一点,但是空白。
(仅供参考,这是第 3 方供应商的产品,所以我必须从 MONEY 开始,然后 return 插入到 MONEY 类型的列中,所有值都必须是 2DP
这是我的例子:
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
谁有神奇的算法?
TIA
马克
这对我来说是成功的。在行级别四舍五入到 1000 似乎产生了一个在四舍五入到 100 时有效的总和。清理并根据您的特定需求进行修改。
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
我需要将发票行拆分为(在本例中)3 个部分(每个部分有 2 位小数),但我已确保拆分的总和等于原始值。
例如:如果我将 5.13 分成 3%、42% 和 55%(分别四舍五入为 2DP),我最终得到:
0.15
2.82
2.15
Sum = 5.12.
我能弄清楚如何做到这一点的唯一方法是使用 case 语句并在除最后一行以外的所有行上拆分为 2DP。
对于最后一行,将所有先前值相加并从原始值中减去。这种方法需要一些子选择。我敢肯定有更好的方法可以做到这一点,但是空白。
(仅供参考,这是第 3 方供应商的产品,所以我必须从 MONEY 开始,然后 return 插入到 MONEY 类型的列中,所有值都必须是 2DP
这是我的例子:
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
谁有神奇的算法?
TIA
马克
这对我来说是成功的。在行级别四舍五入到 1000 似乎产生了一个在四舍五入到 100 时有效的总和。清理并根据您的特定需求进行修改。
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