Подводящие итоги, пропускающие определенные значения - PullRequest
0 голосов
/ 20 июня 2019

Мне нужно вычислить столбец, у которого столбец значений вычтен из столбца Всего, но может пропускать строки до тех пор, пока он не сможет найти меньшее значение. Последовательность относится к датам, поэтому порядок должен быть сохранен. Значение (Потребность) не может быть больше, чем сумма, так как они были удалены ранее.

Это для SQL Server 2016. Мой первоначальный мыслительный процесс состоял в использовании оконных функций и промежуточного итога, но я не могу понять, как пропустить 400 и перейти к 2 строкам ниже. Я включил свои попытки в оператор CASE как TransferQty, а промежуточный итог - как ReferenceCol.

Код для воспроизведения:

DECLARE @i TABLE
(
    sequence INT IDENTITY(1,1)
    ,Total INT
    ,Need INT
)
INSERT INTO @i 
VALUES (500,100)
,(500,200)
,(500,50)
,(500,400)
,(500,50)
,(500,50)

SELECT 
     sequence
    ,Total
    ,Need
    ,CASE 
        WHEN Total - SUM(Need) OVER (ORDER BY sequence) > 0 
        THEN Need 
    ELSE 0 
    END AS TransferQty
    ,Total - SUM(Need) OVER (ORDER BY sequence) as ReferenceCol
FROM @i

Текущие результаты

+----------+-------+------+-------------+--------------+
| Sequence | Total | Need | TransferQty | ReferenceCol |
+----------+-------+------+-------------+--------------+
|        1 |   500 |  100 |         100 |          400 |
|        2 |   500 |  200 |         200 |          200 |
|        3 |   500 |   50 |          50 |          150 |
|        4 |   500 |  400 |           0 |         -250 |
|        5 |   500 |   50 |           0 |         -300 |
|        6 |   500 |   50 |           0 |         -350 |
+----------+-------+------+-------------+--------------+

Желаемые результаты

+----------+-------+------+-------------+--------------+
| Sequence | Total | Need | TransferQty | ReferenceCol |
+----------+-------+------+-------------+--------------+
|        1 |   500 |  100 |         100 |          400 |
|        2 |   500 |  200 |         200 |          200 |
|        3 |   500 |   50 |          50 |          150 |
|        4 |   500 |  400 |           0 |          150 | --skip calc
|        5 |   500 |   50 |          50 |          100 |
|        6 |   500 |   50 |          50 |           50 |
+----------+-------+------+-------------+--------------+

Ответы [ 2 ]

0 голосов
/ 21 июня 2019

Вот решение, которое я выбрал, основанное на "необычном обновлении" из исходного комментария.

DROP TABLE IF EXISTS #i
GO

CREATE TABLE #i 
(
    sequence INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    ,Total INT
    ,Need INT
    ,RunningTransfer INT NULL
)

INSERT INTO #i 
VALUES 
 (500,100,NULL)
,(500,200,NULL)
,(500,50,NULL)
,(500,400,NULL)
,(500,50,NULL)
,(500,50,NULL)
,(500,100,NULL)
,(500,49,NULL)
,(500,50,NULL)

DECLARE @TransferRunningTotal INT

UPDATE #i
    SET @TransferRunningTotal = RunningTransfer = CASE 
                                                    --this skips values larger than running total
                                                    WHEN @TransferRunningTotal < Need THEN @TransferRunningTotal 
                                                    --this creates the running total
                                                    WHEN @TransferRunningTotal > Need THEN @TransferRunningTotal - Need 
                                                    --creates the initial value
                                                    ELSE Total - Need 
                                                 END
FROM #i WITH (TABLOCKX)
 OPTION (MAXDOP 1) 

SELECT sequence
      ,Total
      ,Need
      ,CASE 
            WHEN need <= RunningTransfer THEN Need
            ELSE 0 
      END AS TsfQty
      ,RunningTransfer 
FROM #i 
0 голосов
/ 21 июня 2019

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

        DECLARE @i TABLE
        (
            sequence INT IDENTITY(1,1)
            ,Total INT
            ,Need INT
        )
        INSERT INTO @i 
        VALUES 
         (500,100    )
        ,(500,200   )
        ,(500,50    )
        ,(500,400   )
        ,(500,50    )
        ,(500,50    )

        select  sequence,Total,Need 
        into    #temp_original 
        from    @i

        select  
        b.sequence,b.Total, SUM( a.need) rollingvalue , 
                case when  SUM( a.need) > b.Total 
                        then 0
                     when SUM( a.need) =  b.Total   then SUM( a.need)
                    else b.Total - SUM( a.need)  end  how_much_needed
        into    #temp
        from    @i a
        join    @i b
                on a.sequence < b.sequence + 1
        group by b.sequence,b.Total


        delete from a 
        from    @i a
        join    (
                    select min(sequence) min_sequence
                    from    #temp 
                    where  how_much_needed = 0
                ) minseq
                on minseq.min_sequence = a.sequence


        select  
        b.sequence,b.Total, SUM( a.need) rollingvalue , 
                case when  SUM( a.need) > b.Total 
                        then 0
                     when SUM( a.need) =  b.Total   then SUM( a.need)
                    else b.Total - SUM( a.need)  end  how_much_needed
        into    #temp2
        from    @i a
        join    @i b
                on a.sequence < b.sequence + 1
        group by b.sequence,b.Total

        select   a.sequence,a.Total,a.Need, case when  isnull (b.rollingvalue , 0) = 0 then 0 else case when b.rollingvalue > a.Total then 0 else  a.Need end end as TransferQty  , ISNULL( case when  b.how_much_needed = b.Total then a.Need else b.how_much_needed end,  case when ( select how_much_needed from #temp2 where sequence = a.sequence -1) = a.Total then 0 else (select how_much_needed from #temp where sequence = a.sequence -1) end )  ReferenceCol 
        from    #temp_original a
        LEFT join   #temp2 b
                on a.sequence = b.sequence
        join    #temp c
                on c.sequence = a.sequence

        drop table #temp
        drop table #temp2
        drop table 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...