SQL запускает расчет баланса для группы разделов

#sql #sql-server #tsql #sql-server-2012

Вопрос:

У меня есть требование ограничить количество до определенного уровня. Приведенные ниже данные разбиты на разделы, а также указаны номера строк. Пожалуйста, ознакомьтесь с приведенными ниже текущими данными в таблице

введите описание изображения здесь

Однако результат должен быть таким. Пожалуйста, обратитесь ниже.

введите описание изображения здесь

Текущая вместимость грузовика составляет 16 кол-во. Но если вы видите, что общее количество выделенных ресурсов на уровне разделов равно 17. Поэтому нам нужно вычеркнуть этот дополнительный 1 Кол-во из конечного кол-во распределения динамически на уровне строк, предпочтительно с номером строки 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
 

Комментарии:

1. К сожалению, вы не можете выполнить такого рода агрегацию с помощью оконного (и секционированного) агрегата, вам нужно будет использовать итерацию; скорее всего, с помощью rCTE.

2. В соответствии с руководством по вопросам, пожалуйста, не размещайте изображения кода, данных, сообщений об ошибках и т.д. — Скопируйте или введите текст в вопрос. Пожалуйста, зарезервируйте использование изображений для диаграмм или демонстрации ошибок рендеринга, вещей, которые невозможно точно описать с помощью текста.

3. Как вы вообще это получили Final Allocation Qty 4,9,4 ? почему бы не исправить это в первую очередь, а не исправлять позже

4. @Белка — К сожалению, это не может быть исправлено в первую очередь. Это количество-то, что предлагает система. Но нам нужно ограничить его в зависимости от вместимости грузовика

5. @DaleK опубликовал код, который я пробовал до сих пор

Ответ №1:

Вопреки тому, что было сказано в комментариях, это очень возможно с помощью оконных функций, просто это немного запутанно.

Предполагая, что я правильно понял вашу ситуацию, вы хотите удалить элементы из списка material в порядке их RowNumber следования до тех 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 Материал Вместимость Общее распределение Распределение Скорректированное распределение
1 1 азбука 16 17 4 3
1 2 bac 16 17 9 9
1 3 кэб 16 17 4 4
2 1 азбука 12 17 4 0
2 2 bac 12 17 9 8
2 3 кэб 12 17 4 4
3 1 азбука 2 17 4 0
3 2 bac 2 17 9 0
3 3 кэб 2 17 4 2
4 1 азбука 112 47 14 14
4 2 bac 112 47 19 19
4 3 кэб 112 47 14 14
5 1 азбука 112 173 140 79
5 2 bac 112 173 19 19
5 3 кэб 112 173 14 14

Комментарии:

1. Спасибо, добрый господин @imdave, это отлично работает. Премного благодарен