2016-12-28 35 views
3

我需要關於如何將行值分配給具有相同ID的多行的SQL Server幫助。爲了說明,將值分配給SQL Server中的多行

  • 編號= ProductInventoryCode
  • 數量= QuantityInStock

ForDistribution

Id | Qty | TotalNoOfBranchesWithId 
---+--------+------------------------- 
1 | 40 |  2 
2 | 33 |  3 
3 | 21 |  2 

將接收分佈式值的表

Id | BranchCode | Qty | QtyFromForDistributionTable 
------------------------------------------------------- 
1  101   13   20 
1  102   8   20 
2  101   10   11 
2  102   2   10 
2  103   3   12 
3  101   1   11 
3  102   12   10 

儘可能多的分配應該是每個ID和分支幾乎相等。

我得到了像下面這樣的東西,但有些困惑和迷失的路徑。

with rs as 
(
    select 
     r.*, cume.cumequantity, 
     coalesce(s.shipped, 0) AS shipped 
    from 
     tmpForDistribution r 
    cross apply 
     (SELECT SUM([QuantityInStock]) AS cumequantity 
     FROM tmpForDistribution r2 
     WHERE r2.ProductInventoryCode = r.ProductInventoryCode) cume 
    left join 
     (SELECT ProductInventoryCode, COUNT(ProductInventoryCode) AS shipped 
     FROM tmpDistributed s  
     GROUP BY s.ProductInventoryCode) s ON r.ProductInventoryCode = s.ProductInventoryCode  
) 
select 
    rs.ProductInventoryCode, rs.cumequantity, rs.QuantityInStock, 
    ***"how to distribute"*** 
from rs 

我目前使用SQL Server 2008的

下面是一個示例屏幕輸出

enter image description here

上的結果是145個分行,下面我們用它來分配ForDistributionQty場是3130,我得到了一個分數(DistVal = 21.586),這是不正確的這個問題,它應該是一個整數如21,但是,如果它只是21,那麼21×145只是3045這是害羞的85個單位。

回答

3

這裏我們分配這些值,然後對具有最大數量(任意)的記錄進行最終「調整」。但在一天結束時,數學作品和分佈式數值是正方形的。

注:不知道爲什麼你的樣品中爲什麼ID 2沒有得到均勻分佈

Declare @Table table (Id int,BranchCode int,Qty int) 
Insert Into @Table values 
(1,  101,   13), 
(1,  102,   8), 
(2,  101,   10), 
(2,  102,   2), 
(2,  103,   3), 
(3,  101,   1), 
(3,  102,   12) 

Declare @Dist table (ID int,Qty int) 
Insert Into @Dist values 
(1,40), 
(2,33), 
(3,49) 

;with cte0 as (
     Select A.* 
       ,ToDist = cast(D.Qty as int) 
       ,DistVal = cast(D.Qty as int)/C.Cnt 
       ,RN  = Row_Number() over (Partition By A.ID Order By cast(D.Qty as int)/C.Cnt Desc,A.Qty Desc) 
     From @Table A 
     Join (Select ID,Cnt=count(*) from @Table Group By ID) C on A.ID=C.ID 
     Join @Dist D on A.ID=D.ID ) 
, cte1 as (
     Select ID,AdjVal=Sum(DistVal)-max(ToDist) From cte0 Group By ID 
) 
Select A.ID 
     ,A.BranchCode 
     ,A.Qty 
     ,DistVal = DistVal - case when A.RN<=abs(AdjVal) then 1*sign(AdjVal) else 0 end 
From cte0 A 
Join cte1 B on (A.ID=B.Id) 
Order By 1,2 

返回

ID BranchCode Qty DistVal 
1 101   13 20 
1 102   8 20 
2 101   10 11 
2 102   2 11 
2 103   3 11 
3 101   1 24 
3 102   12 25 
+0

雖然總結結束等於分配的數量,但我只需要整數,我不需要一個均勻分佈的數量(作爲對我的原始需求),我有結束與小數,有沒有什麼辦法去除小數時控制並確保分配的數量相等。 –

+0

@paulpolo你的qty是一個int字段還是別的東西?如果別的DistVal = cast(D.Qty爲int)/C.Cnt –

+0

有很多數量缺失,因爲四捨五入的值會被截斷,例如。小數點的數量是21.56,DistVal = cast(D.Qty as INT)/C.Cnt只有21,所以當你將它乘以分配總數時,會有很多缺失。 –

1

如果你能忍受十進制值,子查詢似乎給更好查詢計劃(在SQL 2014上進行了測試,並帶有一些明智的密鑰,避免了表假脫機和一些額外的索引掃描):

Declare @Table table (Id int,BranchCode int,Qty int, primary key(id, branchcode)) 
Insert Into @Table values 
(1,  101,   13), 
(1,  102,   8), 
(2,  101,   10), 
(2,  102,   2), 
(2,  103,   3), 
(3,  101,   1), 
(3,  102,   12) 

Declare @Dist table (ID int primary key,Qty int) 
Insert Into @Dist values 
(1,40), 
(2,33), 
(3,21) 


SELECT 
    t.id 
    ,t.BranchCode 
    ,t.Qty 
    ,(d.Qty/CAST((SELECT COUNT(*) as cnt FROM @table t2 where t.id = t2.id) AS decimal(10,2))) as DistributedQty 
FROM @Table t 
INNER JOIN @Dist d 
ON d.id = t.Id 

輸出:

Id BranchCode Qty DistributedQty 
1 101   13 20.00000000000 
1 102   82 20.00000000000 
2 101   10 11.00000000000 
2 102   21 11.00000000000 
2 103   31 11.00000000000 
3 101   11 10.50000000000 
3 102   12 10.50000000000 

如果您需要DistributedQty是一個int並保留剩餘物然後我想不出比@約翰卡佩萊蒂的一個更好的解決方案,並指出,不均勻的數量可能不會像正是甚至你可能希望(例如32分發三份將導致12/10/10分發,而不是11/11/10分發)。

+1

我個人更喜歡你提供的精度(一致性很好)+1 –