Sql server 有没有一种方法可以使用窗口函数来保持最小总数为0,而不必使用循环?

Sql server 有没有一种方法可以使用窗口函数来保持最小总数为0,而不必使用循环?,sql-server,tsql,window-functions,Sql Server,Tsql,Window Functions,我试图避免使用循环来获得运行总数。这是一个简化版本;真实版本包括几个类别的小计。我知道我可以使用窗口函数[@Xata2]来实现这一点,但如果将总数限制为非负(即,如果总数为负,则使用0)[@Xata3],我想不出一种非循环方式来实现这一点,因为我设置的任何条件都在当前行上,而不是累计总数 DECLARE @Xata TABLE ( ID INTEGER IDENTITY , result INTEGER

我试图避免使用循环来获得运行总数。这是一个简化版本;真实版本包括几个类别的小计。我知道我可以使用窗口函数[@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
DECLARE@Xata表(
ID整数标识
,结果整数
)
声明@Xata2表(
ID整数标识
,结果整数
,总整数
)
声明@Xata3表(
ID整数标识
,结果整数
,总整数
)
声明@result整数
,@总整数
,@计数器整数
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
--@Xata2:窗口功能
插入@Xata2
选择结果
,总和(结果)超过(按ID排序)
来自@Xata
选择ID
,结果
,总计为总计×2×负
来自@Xata2
设置@Counter=0
当@Counter<(从@Xata中选择最大值(ID)
开始
设置@Counter+=1
从@Xata中选择@result=result,其中ID=@Counter
设置@total=ISNULL((从@Xata3中选择total,其中ID=@Counter-1),0)
插入@Xata3
选择@result
,IIF(@result+@total<0,0,@result+@total)
结束
选择ID
,结果
,总计为总计×3
来自@Xata3
编辑

我把整件事都写进了另一个连续的总数里

什么时候

顺便说一句,我希望每个人都像这样工作

 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
DECLARE@Xata表(
ID整数标识
,结果整数
)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)
插入@Xata(结果)选择圆形(RAND()*9-4.5,0)

选择x.ID,x.result,x.RT1,SUM(IIF)(x.RT1我的第一次尝试没有正确返回,谢谢@Menno的提示

使用递归CTE尝试这种方法

结果

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

尝试将
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
选择id、结果、,
当[sum]<0时,则为0,否则为[sum]
从(
选择id,
结果,,
总和(结果)超过(按id排序)[总和]
从MyTable
)a

您能解释一下您的查询背后的逻辑以及它应该做什么吗?这是我很久以来看到的最好的复制。Upvote@Nick.McDermaid我也很欣赏重新编程,但我更喜欢固定值,而不是固定值输出。在这里使用随机值会使您更难看到解决方案是否正确返回…一个是的,我这边有+1。@DaveX让我们假设第7行包含一个结果
-6
。应该
total\ux3\uNoneg
导致
0
5
?@Menno,我想第7到8行回答了你的问题。我们有一个1,一个结果
-3
,在那里我们看到一个
0
。我认为这是:计算减法,但永远不会低于零。这不会导致第2行的值
1
,对吗?样本数据是随机的,因此第2行总是不同的。但对于
1
的输入值(在字段
r1
中),是的,它返回
1
。你为什么不自己运行代码?嗯,等一下-你现在是我重新检查的时候了,你是对的,它不返回OP是什么after@Nick.McDermaid不,您编辑的版本未按预期返回。您可以尝试使用我的答案中的模型,以使用与问题中使用的值相同的值…复杂性与t有关他在示例第7行中给出了数据。@DaveX所追求的逻辑是,运行总数可能不会低于0。+1我也没有看到使用窗口函数的有效方法,递归CTE可能是最优雅的解决方案。这正是我必须更改它之前的方法。OP希望使用负值,但不低于零。因此,它是仅仅对正值求和是不够的…在给定的示例中,
-4
用于从
5
1
。如果
5
是4或更少,它应该降到
0
…抱歉,但您的编辑无法修复此问题。您可以使用我的答案的模型尝试此操作…这还不足以让ne大吃一惊负和值。。。
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