TSQL递归存储过程添加不起作用

时间:2014-12-23 10:12:29

标签: database tsql stored-procedures recursion sql-server-2012

我的存储过程遇到了问题。它应该从给定的位置添加所有孩子,子孙等的值并返回它。目前它返回的只有NULL

这是将使用存储过程的表的示例。

稍后我想将操作符Bool实现到存储过程中。如果是NULL,则在计算中忽略saldo。如果它是0,则saldo被否定地使用,如果它是1,则saldo被正面使用。

id  pos             operpos     saldo   operator
-------------------------------------------------
1   blue            NULL        NULL    NULL
2   lightblue       blue        NULL    1
3   darkblue        blue        25.00   1
4   skyblue         lightblue   12.00   1
5   babyblue        lightblue   -12.00  0
6   greyblue        lightblue   22.00   1
7   royalblue       darkblue    121.00  1
8   navyblue        darkblue    20.00   1
9   sailorsblue     navyblue    23.00   0
10  captainsblue    navyblue    33.00   1

这是calctotal(darkblue)的存储过程应该计算的内容:

darkblue        +25
 royalblue      +121
 navyblue       +20
  sailorsblue   -23 //because operator = 0
  captainsblue  +33
OUTPUT          176

这是我目前的存储过程:

ALTER PROCEDURE [dbo].[calctotal]
        //DECLARE INPUT AND OUTPUT
       @number nvarchar(255),
       @total NUMERIC(20,2) OUTPUT
AS
BEGIN
     //DECLARE THE VARIABLES
     DECLARE @pos NVARCHAR(255) = NULL;
     DECLARE @saldo NUMERIC(20,2) =  NULL;
     DECLARE @tmptotal NUMERIC(20,2)
     DECLARE @tmptotal2 NUMERIC(20,2) = 0;

     //LOAD DATA INTO CURSOR
     DECLARE cur CURSOR LOCAL for
        SELECT pos, saldo  
        FROM test 
        WHERE operpos = @number

     //START CURSOR AND FETCH NEXT
     OPEN CUR

     FETCH NEXT FROM CUR INTO @pos, @tmptotal2

     //WHEN NEW ITEM HAS BEEN LOADED
     WHILE @@FETCH_STATUS = 0
     BEGIN
         //ADD VALUE TO TMPTOTAL
         SET @tmptotal = @tmptotal2 + @tmptotal;

         //RECURSIVE PART SO FUNCTION APPLIES TO CHILDREN
         EXEC calctotal @pos, @tmptotal;
     END;

     close cur
     deallocate cur

     //THE OUTPUT OF TOTAL IS SET TO THE VALUE OF THE VARIABLE
     SET @total = @tmptotal;
END

你们有没有和想法代码可能出错和/或如何纠正它?有关如何实现Operator Boolean的任何提示,我将非常高兴!

提前感谢您的帮助

编辑:我正在使用SQL Server 2012

1 个答案:

答案 0 :(得分:1)

试试这个:

;with cte as
(select pos, operpos, saldo, [operator], 0 as level
 from tbl
 where pos = 'darkblue'
 union all
 select t.pos,t.operpos, t.saldo, t.[operator], c.level + 1
 from tbl t 
 inner join cte c on c.pos = t.operpos
)

select sum (
case 
when [operator] = 0 then (-1 * saldo) 
when [operator] = 1 then saldo 
else 0 
end) as totalsum from cte

这是一个递归的公用表表达式(CTE),可从SQL Server 2005开始提供。我们基本上检索了所有孩子的根值' darkblue'然后根据operator字段进行条件求和。您可以代替硬编码,而不是传递参数:

...
where pos = @pos
...

请注意,此方法将数据作为一个集处理,并且无需手动处理游标。

Demo