SQL 运行分区组的余额计算
SQL running balance calculation for a partition group
我有将数量限制在一定水平的要求。以下数据已分区,还提供了行号。请参考下面这是table
中的当前数据
但是输出应该是这样的。请参考以下内容。
当前卡车容量为 16 辆。但是,如果您看到分区级别的总分配数量为 17。因此我们需要在行级别动态地从最终分配数量中减去额外的 1 数量,最好从 Rownumber 1..2..3 像这样。我曾尝试使用 while 循环完成 运行 总计,但没有成功
到目前为止我已经尝试过什么
DECLARE @GroupCount INT
SET @GroupCount = (SELECT MAX(PartitionNum) FROM Allocation_Table)
DECLARE @RowCount INT
-- Declare an iterator
DECLARE @I INT,@J int
--Initialize the iterator
SET @I =1
WHILE (@I <= @GroupCount)
BEGIN
SET @RowCount = (SELECT MAX(RowNumber) FROM Allocation_Table WHERE PartitionNum=@I)
DECLARE @BS float=0
SELECT @BS = cast([Remainder Qty to be dropped] as float) FROM Allocation_Table WHERE PartitionNum=@I
SET @J = 1
WHILE (@J <= @RowCount)
BEGIN
--PRINT @I
declare @BV float, @Qty float,@flg bit,@Ibs float, @EV float
SELECT @Qty=[Final Allocation Qty] FROM Allocation_Table WHERE PartitionNum=@I and RowNumber=@J
set @IBS=@BS
SET @BS=case when (@BS>=@Qty) then @BS-@Qty else @BS end
SET @flg=case when (@IBS>=@Qty) then 1 when (@IBS<@Qty) and @IBS>0 then 1 else 0 end
set @BS= case when (@IBS<@Qty) then 0 else @BS end
update Allocation_Table set BS_Cal=@BS ,Flag=@flg WHERE RowNumber = @J and PartitionNum=@I
SET @J = @J + 1
END
SET @I = @I + 1
与评论中所说的相反,使用 window 函数是很有可能的,只是有点复杂。
假设我正确理解了您的情况,您希望按照 RowNumber
的顺序从 material
中删除项目,直到达到 Truck capacity
。为此,只需要根据上一行中的值进行一些 运行 聚合和条件数学运算:
查询
declare @t table(pn int,rn int,Material varchar(100),Allocation int,Capacity int);
insert into @t values
(1,1,'abc',4,16)
,(1,2,'bac',9,16)
,(1,3,'cab',4,16)
,(2,1,'abc',4,12)
,(2,2,'bac',9,12)
,(2,3,'cab',4,12)
,(3,1,'abc',4,2)
,(3,2,'bac',9,2)
,(3,3,'cab',4,2)
,(4,1,'abc',14,112)
,(4,2,'bac',19,112)
,(4,3,'cab',14,112)
,(5,1,'abc',140,112)
,(5,2,'bac',19,112)
,(5,3,'cab',14,112)
;
with d as
(
select *
,sum(Allocation) over (partition by pn) as TotalAllocation
,sum(Allocation) over (partition by pn) - Capacity as TotalOverage
,sum(Allocation) over (partition by pn)
- Capacity
- sum(Allocation) over (partition by pn order by rn)
as Overage
from @t
)
select pn
,rn
,Material
,Capacity
,TotalAllocation
,Allocation
,case when Overage > 0
then 0
else case when lag(Overage,1) over (partition by pn order by rn) is null
then case when Allocation < (Allocation - TotalOverage)
then Allocation
else Allocation - TotalOverage
end
else
case when lag(Overage,1,0) over (partition by pn order by rn) > 0
then Allocation - lag(Overage,1,0) over (partition by pn order by rn)
else Allocation
end
end
end as AdjustedAllocation
from d
order by pn
,rn;
输出
pn
rn
Material
Capacity
TotalAllocation
Allocation
AdjustedAllocation
1
1
abc
16
17
4
3
1
2
bac
16
17
9
9
1
3
cab
16
17
4
4
2
1
abc
12
17
4
0
2
2
bac
12
17
9
8
2
3
cab
12
17
4
4
3
1
abc
2
17
4
0
3
2
bac
2
17
9
0
3
3
cab
2
17
4
2
4
1
abc
112
47
14
14
4
2
bac
112
47
19
19
4
3
cab
112
47
14
14
5
1
abc
112
173
140
79
5
2
bac
112
173
19
19
5
3
cab
112
173
14
14
我有将数量限制在一定水平的要求。以下数据已分区,还提供了行号。请参考下面这是table
中的当前数据但是输出应该是这样的。请参考以下内容。
当前卡车容量为 16 辆。但是,如果您看到分区级别的总分配数量为 17。因此我们需要在行级别动态地从最终分配数量中减去额外的 1 数量,最好从 Rownumber 1..2..3 像这样。我曾尝试使用 while 循环完成 运行 总计,但没有成功
到目前为止我已经尝试过什么
DECLARE @GroupCount INT
SET @GroupCount = (SELECT MAX(PartitionNum) FROM Allocation_Table)
DECLARE @RowCount INT
-- Declare an iterator
DECLARE @I INT,@J int
--Initialize the iterator
SET @I =1
WHILE (@I <= @GroupCount)
BEGIN
SET @RowCount = (SELECT MAX(RowNumber) FROM Allocation_Table WHERE PartitionNum=@I)
DECLARE @BS float=0
SELECT @BS = cast([Remainder Qty to be dropped] as float) FROM Allocation_Table WHERE PartitionNum=@I
SET @J = 1
WHILE (@J <= @RowCount)
BEGIN
--PRINT @I
declare @BV float, @Qty float,@flg bit,@Ibs float, @EV float
SELECT @Qty=[Final Allocation Qty] FROM Allocation_Table WHERE PartitionNum=@I and RowNumber=@J
set @IBS=@BS
SET @BS=case when (@BS>=@Qty) then @BS-@Qty else @BS end
SET @flg=case when (@IBS>=@Qty) then 1 when (@IBS<@Qty) and @IBS>0 then 1 else 0 end
set @BS= case when (@IBS<@Qty) then 0 else @BS end
update Allocation_Table set BS_Cal=@BS ,Flag=@flg WHERE RowNumber = @J and PartitionNum=@I
SET @J = @J + 1
END
SET @I = @I + 1
与评论中所说的相反,使用 window 函数是很有可能的,只是有点复杂。
假设我正确理解了您的情况,您希望按照 RowNumber
的顺序从 material
中删除项目,直到达到 Truck capacity
。为此,只需要根据上一行中的值进行一些 运行 聚合和条件数学运算:
查询
declare @t table(pn int,rn int,Material varchar(100),Allocation int,Capacity int);
insert into @t values
(1,1,'abc',4,16)
,(1,2,'bac',9,16)
,(1,3,'cab',4,16)
,(2,1,'abc',4,12)
,(2,2,'bac',9,12)
,(2,3,'cab',4,12)
,(3,1,'abc',4,2)
,(3,2,'bac',9,2)
,(3,3,'cab',4,2)
,(4,1,'abc',14,112)
,(4,2,'bac',19,112)
,(4,3,'cab',14,112)
,(5,1,'abc',140,112)
,(5,2,'bac',19,112)
,(5,3,'cab',14,112)
;
with d as
(
select *
,sum(Allocation) over (partition by pn) as TotalAllocation
,sum(Allocation) over (partition by pn) - Capacity as TotalOverage
,sum(Allocation) over (partition by pn)
- Capacity
- sum(Allocation) over (partition by pn order by rn)
as Overage
from @t
)
select pn
,rn
,Material
,Capacity
,TotalAllocation
,Allocation
,case when Overage > 0
then 0
else case when lag(Overage,1) over (partition by pn order by rn) is null
then case when Allocation < (Allocation - TotalOverage)
then Allocation
else Allocation - TotalOverage
end
else
case when lag(Overage,1,0) over (partition by pn order by rn) > 0
then Allocation - lag(Overage,1,0) over (partition by pn order by rn)
else Allocation
end
end
end as AdjustedAllocation
from d
order by pn
,rn;
输出
pn | rn | Material | Capacity | TotalAllocation | Allocation | AdjustedAllocation |
---|---|---|---|---|---|---|
1 | 1 | abc | 16 | 17 | 4 | 3 |
1 | 2 | bac | 16 | 17 | 9 | 9 |
1 | 3 | cab | 16 | 17 | 4 | 4 |
2 | 1 | abc | 12 | 17 | 4 | 0 |
2 | 2 | bac | 12 | 17 | 9 | 8 |
2 | 3 | cab | 12 | 17 | 4 | 4 |
3 | 1 | abc | 2 | 17 | 4 | 0 |
3 | 2 | bac | 2 | 17 | 9 | 0 |
3 | 3 | cab | 2 | 17 | 4 | 2 |
4 | 1 | abc | 112 | 47 | 14 | 14 |
4 | 2 | bac | 112 | 47 | 19 | 19 |
4 | 3 | cab | 112 | 47 | 14 | 14 |
5 | 1 | abc | 112 | 173 | 140 | 79 |
5 | 2 | bac | 112 | 173 | 19 | 19 |
5 | 3 | cab | 112 | 173 | 14 | 14 |