Есть ли способ использовать оконную функцию, чтобы сохранить минимальный итог 0 вместо того, чтобы иметь цикл? - PullRequest
3 голосов
/ 15 октября 2019

Я пытаюсь избежать использования цикла для получения промежуточного итога. Это упрощенная версия;реальная версия включает промежуточные итоги по нескольким категориям. Я знаю, что могу сделать это, используя оконную функцию [@ Xata2], но я не могу придумать, как сделать это без цикла, если вы ограничите итоговое значение неотрицательным (т. Е. Если оно отрицательное, используйте 0вместо этого) [@ Xata3], потому что любые условия, которые я ставлю, относятся к текущей строке, а не кумулятивному итогу.

    DECLARE   @Xata TABLE (
          ID            INTEGER IDENTITY
        , result        INTEGER
        )

    DECLARE   @Xata2 TABLE (
          ID            INTEGER IDENTITY
        , result        INTEGER
        , total         INTEGER
        )

    DECLARE   @Xata3 TABLE (
          ID            INTEGER IDENTITY
        , result        INTEGER
        , total         INTEGER
        )

    DECLARE   @result   INTEGER
            , @total    INTEGER
            , @Counter  INTEGER

    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
    INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)

    -- @Xata2: WINDOWING FUNCTION

    INSERT INTO @Xata2
        SELECT    result
                , SUM(result) OVER (ORDER BY ID)
            FROM @Xata

    SELECT    ID
            , result
            , total AS total_x2_neg
        FROM @Xata2

    SET @Counter = 0

    WHILE @Counter < (SELECT MAX(ID) FROM @Xata)
        BEGIN
            SET @Counter += 1

            SELECT @result = result FROM @Xata WHERE ID = @Counter
            SET @total = ISNULL((SELECT total FROM @Xata3 WHERE ID = @Counter - 1), 0)

            INSERT INTO @Xata3
                SELECT    @result
                        , IIF(@result + @total < 0, 0, @result + @total)

        END

    SELECT    ID
            , result
            , total AS total_x3_noneg
        FROM @Xata3

enter image description here

Ответы [ 3 ]

1 голос
/ 15 октября 2019

Моя первая попытка не вернулась правильно, спасибо @Menno за подсказку.

Попробуйте этот подход с рекурсивным CTE

DECLARE   @Xata TABLE (ID INTEGER IDENTITY
                      ,result INTEGER);

INSERT INTO @Xata (result) VALUES(-3),(1),(2),(2),(0),(0),(-4),(-3),(2),(3);

WITH recCte AS
(
    SELECT ID
          ,result
          ,CASE WHEN result>0 THEN result ELSE 0 END AS runningTotalNoNeg 
    FROM @Xata 
    WHERE ID=1

    UNION ALL

    SELECT d.ID
          ,d.result
          ,CASE WHEN r.runningTotalNoNeg + d.result > 0 then r.runningTotalNoNeg + d.result ELSE 0 END
    FROM @Xata d
    INNER JOIN recCte r ON d.ID=r.ID+1
)
SELECT *
FROM recCte;

результатом

ID  rt  runningTotalNoNeg
1  -3   0
2   1   1
3   2   3
4   2   5
5   0   5
6   0   5
7  -4   1
8  -3   0
9   2   2
10  3   5
0 голосов
/ 15 октября 2019

Попробуйте использовать sum оконную функцию с оператором case:

select id, result,
       case when [sum] < 0 then 0 else [sum]
from (
    select id,
           result,
           sum(result) over (order by id) [sum]
    from MyTable
) a
0 голосов
/ 15 октября 2019

РЕДАКТИРОВАТЬ

Я завернул все это в другой промежуточный итог.

Когда

ОТЛИЧНО repro кстати- Я бы хотел, чтобы все работали так

 DECLARE   @Xata TABLE (
      ID            INTEGER IDENTITY
    , result        INTEGER
    )



INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)
INSERT INTO @Xata (result) SELECT ROUND(RAND()* 9 - 4.5, 0)


SELECT x.ID, x.result, x.RT1, SUM(IIF(x.RT1<0,0,x.RT1)) OVER (ORDER BY ID) as RT2
from (
        SELECT  ID,  result
            , SUM(result) OVER (ORDER BY ID) as RT1
        FROM @Xata
    ) as x
ORDER BY x.ID
...