递归自连接求和
Sum on a Recursive Self-Join
我在以下位置找到了一篇非常有用的文章:
Simplest way to do a recursive self-join in SQL Server?
假设在这个例子中有另一个名为 "Quantity" 的列存储整数,如下所示:
PersonID | Initials | ParentID | Quantity
1 CJ NULL 1
2 EB 1 2
3 MB 1 1
4 SW 2 1
5 YT NULL 1
6 IS 5 1
如果我请求 CJ 的层次结构,它将是
PersonID | Initials | ParentID | Quantity | HasSubordinate
1 CJ NULL 2 1
2 EB 1 1 1
3 MB 1 1 1
4 SW 2 1 0
HasSubordinate 列指定层次结构中的最后一个个体。我想显示层次结构中的最后一个人,并将前一行的数量相乘。在这种情况下,数量将为 2 (2 x 1 x 1 x 1 = 2)。
PersonID | Initials | ParentID | Quantity | HasSubordinate
4 SW 2 2 0
我的代码:
WITH q AS
(
SELECT *
FROM mytable
WHERE PersonID = 1
UNION ALL
SELECT m.*
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
WHERE HasSubordinate = 0
非常感谢任何帮助!!
您可以在递归 cte 中添加一个新字段并在迭代时相乘:
WITH q AS
(
SELECT *,Quantity AS Tot_Qty
FROM mytable
WHERE PersonID = 1
UNION ALL
SELECT m.*,m.Quantity * q.Tot_Qty AS Tot_Qty
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
WHERE HasSubordinate = 0
注意:这会让您 2 x 1 x 1
而不是 2 x 1 x 1 x 1
因为您使用的是 ParentID
.
时不时地,有人抱怨没有 MULT
聚合函数。也许有一天会有,但在那之前,我们必须作弊。以下是基于 LOG(a * b * c ) = LOG( a ) + LOG( b ) + LOG( c ) 的事实。不幸的是,它需要一个额外的 CTE 级别(虽然不是递归的)但它最终会得出一个答案。
with
List( PersonID, Initials, ParentID, Qty )as(
select 1, 'CJ', null, 1 union all
select 2, 'EB', 1, 2 union all
select 3, 'MB', 1, 3 union all
select 4, 'SW', 2, 4 union all
select 5, 'YT', null, 2 union all
select 6, 'IS', 5, 5
),
CTE( PersonID, Initials, ParentID, Qty, Root )as(
select l.PersonID, l.Initials, l.ParentID, l.Qty, l.PersonID
from List l
where l.ParentID is null
--and l.Initials = 'CJ'
union all
select l.PersonID, l.Initials, l.ParentID, l.Qty, c.Root
from CTE c
join List l
on l.ParentID = c.PersonID
),
Logs( PersonID, Initials, ParentID, Qty, Root, SumLog )as(
select *, sum( log( Qty )) over( partition by Root)
from CTE
)
select *, exp( SumLog ) as Mult
from Logs
order by PersonID;
生成此结果:
PersonID Initials ParentID Qty Root SumLog Mult
-------- -------- -------- --- ---- ---------------- ----
1 CJ NULL 1 1 3.17805383034795 24
2 EB 1 2 1 3.17805383034795 24
3 MB 1 3 1 3.17805383034795 24
4 SW 2 4 1 3.17805383034795 24
5 YT NULL 2 5 2.30258509299405 10
6 IS 5 5 5 2.30258509299405 10
这满足所述要求,拉出最后一行将使所有 QTY 的总数相乘——它们都具有该值。也许聪明的人可以生成 运行 总数。我会把它留作练习(意思是我懒得自己尝试)。
我在以下位置找到了一篇非常有用的文章: Simplest way to do a recursive self-join in SQL Server?
假设在这个例子中有另一个名为 "Quantity" 的列存储整数,如下所示:
PersonID | Initials | ParentID | Quantity
1 CJ NULL 1
2 EB 1 2
3 MB 1 1
4 SW 2 1
5 YT NULL 1
6 IS 5 1
如果我请求 CJ 的层次结构,它将是
PersonID | Initials | ParentID | Quantity | HasSubordinate
1 CJ NULL 2 1
2 EB 1 1 1
3 MB 1 1 1
4 SW 2 1 0
HasSubordinate 列指定层次结构中的最后一个个体。我想显示层次结构中的最后一个人,并将前一行的数量相乘。在这种情况下,数量将为 2 (2 x 1 x 1 x 1 = 2)。
PersonID | Initials | ParentID | Quantity | HasSubordinate
4 SW 2 2 0
我的代码:
WITH q AS
(
SELECT *
FROM mytable
WHERE PersonID = 1
UNION ALL
SELECT m.*
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
WHERE HasSubordinate = 0
非常感谢任何帮助!!
您可以在递归 cte 中添加一个新字段并在迭代时相乘:
WITH q AS
(
SELECT *,Quantity AS Tot_Qty
FROM mytable
WHERE PersonID = 1
UNION ALL
SELECT m.*,m.Quantity * q.Tot_Qty AS Tot_Qty
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
WHERE HasSubordinate = 0
注意:这会让您 2 x 1 x 1
而不是 2 x 1 x 1 x 1
因为您使用的是 ParentID
.
时不时地,有人抱怨没有 MULT
聚合函数。也许有一天会有,但在那之前,我们必须作弊。以下是基于 LOG(a * b * c ) = LOG( a ) + LOG( b ) + LOG( c ) 的事实。不幸的是,它需要一个额外的 CTE 级别(虽然不是递归的)但它最终会得出一个答案。
with
List( PersonID, Initials, ParentID, Qty )as(
select 1, 'CJ', null, 1 union all
select 2, 'EB', 1, 2 union all
select 3, 'MB', 1, 3 union all
select 4, 'SW', 2, 4 union all
select 5, 'YT', null, 2 union all
select 6, 'IS', 5, 5
),
CTE( PersonID, Initials, ParentID, Qty, Root )as(
select l.PersonID, l.Initials, l.ParentID, l.Qty, l.PersonID
from List l
where l.ParentID is null
--and l.Initials = 'CJ'
union all
select l.PersonID, l.Initials, l.ParentID, l.Qty, c.Root
from CTE c
join List l
on l.ParentID = c.PersonID
),
Logs( PersonID, Initials, ParentID, Qty, Root, SumLog )as(
select *, sum( log( Qty )) over( partition by Root)
from CTE
)
select *, exp( SumLog ) as Mult
from Logs
order by PersonID;
生成此结果:
PersonID Initials ParentID Qty Root SumLog Mult
-------- -------- -------- --- ---- ---------------- ----
1 CJ NULL 1 1 3.17805383034795 24
2 EB 1 2 1 3.17805383034795 24
3 MB 1 3 1 3.17805383034795 24
4 SW 2 4 1 3.17805383034795 24
5 YT NULL 2 5 2.30258509299405 10
6 IS 5 5 5 2.30258509299405 10
这满足所述要求,拉出最后一行将使所有 QTY 的总数相乘——它们都具有该值。也许聪明的人可以生成 运行 总数。我会把它留作练习(意思是我懒得自己尝试)。