SQL Server 2012 Adding/Subtracting 具有函数的层次结构中的值

SQL Server 2012 Adding/Subtracting Values in Hierarchy with Function

我在评估我的分层数据时遇到了问题,如果你们有任何提示,我将非常高兴。

我的 table 有 4 列:ID 是不言自明的,parentID 创建层次结构,每个 child 只有一个 parent, value 只是货币的数值(某些行的值将是 NULL),最后 operator 可以是 3 个值 0, 1 and NULL (我希望它对应于-, + and ignore 但稍后会详细介绍)。运营商直接公开与child关联的运营商与其parent.

例如ID, ParentID, Operator, Value 23, 2, 1, 2.22 具有运算符 1,因此在尝试使用 ID = 2

计算其 parent 的值时应添加

我的函数的目的是通过递归检查所有 children 来计算给定 IDvalue,如果 operator1 或者如果是0 减去 值(如果是NULL值将被忽略)。

到目前为止,我已经编写了一个带有递归 cte 的函数,它找到给定 ID 的所有 children 和 sub-children 集合它们合在一起 table 然后在应用 case.

之后求和
function [dbo].[total](
@id int)
returns NUMERIC(20,2)
AS
BEGIN
declare @total numeric(20,2);

cte as(
SELECT id, parentid, operator, value, 0 as level
    FROM data
    WHERE pos = @pos
    union all
 select t.id, t.parentid, t.operator, t.value, c.level + 1
 FROM
    data t
 inner join cte c on c.id = t.parentid)

 SELECT @total = (select sum (case when operator = 0 then (5 * value) when operator = 1 then value/100 else 0 end) from cte);
RETURN @total
END

此功能在一定程度上有效,例如在这个例子中,dbo.total(1) 会给我正确的结果 1 -2.5+3.5

ID       Operator  Value  ParentID
1        1         NULL    -
 2       1         NULL    1
  3      0         2.5     2
  4      1         3.5     2

然而在其他情况下,这并不适用。在这个例子中,它会 return 一个 5 + 2.5 + 2.5 = 10 的值,尽管我希望它 "recognize" 而 34 的 parent ( 2) 的运算符为 0,因此应减去它们的值,从而导致不同的计算 5 - (2.5 + 2.5) = 0

ID       Operator  Value  ParentID
1        1         5    -
 2       0         NULL    1
  3      1         2.5     2
  4      1         2.5     2

我希望我不是第一个遇到这个问题的人,我期待着您对这个话题的任何回答。如果您有任何问题,请随时问我。 :) 非常感谢!

我终于找到了解决这个问题的方法。我仍在使用相同的 CTE。我刚刚添加了一个 WHILE 循环,这样我就可以从 "youngest" child 到最旧的(最小级别到最大级别)

现在是这样工作的:

function [dbo].[total](@id int)
returns NUMERIC(20,2)
AS
BEGIN
declare @total numeric(20,2);
declare @level int;
declare @cte table (id int, parentid int,operator bit,value numeric(20,2),level int);

--the same cte that i had used earlier
cte as
(SELECT id, parentid, operator, value, 0 as level
    FROM
    data
    WHERE id = @id
union all
select t.id, t.parentid, t.operator, t.value, c.level + 1
FROM
    data t
inner join cte c on c.id = t.parentid
)

--write the calculated cte to @cte
insert into @cte select * from cte


--This is where the magic happens. The while loop uses the fact that all
children were given a level higher than 0 in the cte.
While (select max(level) from @cte)>0
BEGIN
select @level = max(level) from @cte
UPDATE @cte
SET value = t.summe

from @cte AS ctable inner join(
SELECT parentid, sum(case when dtable.operator = 0 then (-1 * dtable.value)
when dtable.operator = 1 then dtable.value else 0 end) summe
FROM @cte dtable
group by parentid
)
as t
on t.parentid = ctable.id
WHERE level = @level -1


--delete the rows, with the current max level.
This causes the loop to work and acts like an i-- for my while function
DELETE  @cte
FROM @cte ctable
WHERE ctable.level = @level

END


SELECT @total = (select sum (value) from @cte);
RETURN @total
END