我目前正在尝试使用百分比列拆分一个值。但由于大多数百分比值是1/3,我无法在值中得到两个小数点100%的aboslute。例如:
Product Supplier percentage totalvalue customer_split
decimal(15,14) (decimal(18,2) decimal(18,2)
-------- -------- ------------ --------------- ---------------
Product1 Supplier1 0.33 10.00 3.33
Product1 Supplier2 0.33 10.00 3.33
Product1 Supplier3 0.33 10.00 3.33
所以,这里我们在值列中缺少0.01,供应商希望随机将任何一个供应商的这个缺失值0.01。我一直试图用两组带有临时表的SQL来完成这项工作,但是有没有简单这样做的方法。如果可能的话,如何在上述行之一的百分比列中获得0.34? 0.01是可忽略的值,但是当值列为1000000000时,它是重要的。
答案 0 :(得分:3)
运行它,它会给出如何解决问题的想法。 我创建了一个名为orders的表,其ID很容易理解:
create table orders(
customerID int)
insert into orders values(1)
go 3
insert into orders values(2)
go 3
insert into orders values(3)
go 3
这些值代表您拥有的33%
1 33.33
2 33.33
3 33.33
现在:
create table #tempOrders(
customerID int,
percentage numeric(10,2))
declare @maxOrder int
declare @maxOrderID int
select @maxOrderID = max(customerID) from orders
declare @total numeric(10,2)
select @total =count(*) from orders
insert into #tempOrders
select customerID, cast(100*count(*)/@total as numeric(10,2)) as Percentage
from orders
group by customerID
update #tempOrders set percentage = percentage + (select 100-sum(Percentage) from #tempOrders)
where customerID =@maxOrderID
此代码将基本上计算百分比和具有最大ID的顺序,然后它得到100与百分比之和的差异,并将其添加到具有maxID(您的随机顺序)的订单
select * from #tempOrders
1 33.33
2 33.33
3 33.34
答案 1 :(得分:3)
听起来你在这里正在做某种类型的“分配”。这是一个常见的问题,只要您尝试从较高的粒度分配到较低的粒度,并且您需要能够正确地重新聚合到总值。
当处理较大的分数时,这会成为一个更大的问题。
例如,如果我尝试将总值(例如$ 55.30除以8)除以八个桶中的每一个得到$ 6.9125的十进制值。我应该把一个回合到6.92美元,剩下的到6.91美元吗?如果我这样做,我将失去一分钱。我不得不将第一轮赔率为6.93美元,其他赔率为6.91美元。当你添加更多的桶来划分时,这会变得更糟。
此外,当你开始回合时,你会引入诸如“33.339应该舍入到33.34还是33.33?”这样的问题。
如果您的业务逻辑是这样的,您只想要超过2个有效余数可能存在,并将其“随机”添加到其中一个美元值,这样您就不会丢失任何美分,@ Diego在右侧跟踪这个。
在纯SQL中执行它有点困难。首先,你的百分比不是1/3,它是.33,它将产生9.9的总值,而不是10.我会将其存储为比率或高精度十进制字段(.33333333333333)。 / p>
P S PCT Total
-- -- ------------ ------
P1 S1 .33333333333 10.00
P2 S2 .33333333333 10.00
P3 S3 .33333333333 10.00
SELECT
BaseTable.P, BaseTable.S,
CASE WHEN BaseTable.S = TotalTable.MinS
THEN BaseTable.BaseAllocatedValue + TotalTable.Remainder
ELSE BaseTable.BaseAllocatedValue
END As AllocatedValue
FROM
(SELECT
P, S, FLOOR((PCT * Total * 100)) / 100 as BaseAllocatedValue,
FROM dataTable) BaseTable
INNER JOIN
(SELECT
P, MIN(S) AS MinS,
SUM((PCT * Total) - FLOOR((PCT * Total * 100)) / 100) as Remainder,
FROM dataTable
GROUP BY P) as TotalTable
ON (BaseTable.P = TotalTable.P)
根据每个供应商的产品总数,您的计算结果似乎相等。如果是,则删除百分比可能是有利的,而只是将每个供应商的项目数存储在表格中。
如果还可以存储一个标志,指示应该为其应用余数值的行,则可以根据该标志而不是随机分配。
答案 2 :(得分:1)
使用窗口聚合函数这应该是一项简单的任务。您可能已经将它们用于计算customer_split
:
totalvalue / COUNT(*) OVER (PARTITION BY Product) as customer_split
现在总结一下customer_splits,如果总值有差异,则将其添加(或减去)到一个随机行。
SELECT
Product
,Supplier
,totalvalue
,customer_split
+ CASE
WHEN COUNT(*)
OVER (PARTITION BY Product
ROWS UNBOUNDED PRECEDING) = 1 -- get a random row, using row_number/order you might define a specific row
THEN totalvalue - SUM(customer_split)
OVER (PARTITION BY Product)
ELSE 0
END
FROM
(
SELECT
Product
,Supplier
,totalvalue
,totalvalue / COUNT(*) OVER (PARTITION BY Product) AS customer_split
FROM dropme
) AS dt
答案 3 :(得分:0)
经过多次试验和测试,我认为我找到了更好的解决方案
<强>观强>
这是我的代码的一部分
Select your_cols
,(Select count(*) from [tbl_Partner_Entity] pa_et where [E_ID] =@E_ID)
AS cnt_all
,(ROW_NUMBER() over ( order by pe.p_id)) as row_num
,Case when (
(ROW_NUMBER() over ( order by pe.p_id)) <
(Select count(*) from [tbl_Partner_Entity] pa_et where [E_ID] =@E_ID))
then round(([partnership_partners_perc]*100),2)
else
100-
((select sum(round(([partnership_partners_perc]*100),2)) FROM [dbo].
[tbl_Partner_Entity] PEE where [E_ID] =@E_ID and pee.P_ID != pe.P_ID))
end AS [partnership_partners_perc_Last]
FROM [dbo].[tbl_Partner_Entity] PE
where [E_ID] =@E_ID