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 来计算给定 ID
的 value
,如果 operator
是 1
加 或者如果是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" 而 3
和 4
的 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
我在评估我的分层数据时遇到了问题,如果你们有任何提示,我将非常高兴。
我的 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
我的函数的目的是通过递归检查所有 children 来计算给定 ID
的 value
,如果 operator
是 1
加 或者如果是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" 而 3
和 4
的 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