递归自联接的总和

时间:2015-02-23 18:17:10

标签: sql recursion

我找到了一篇非常有帮助的文章: 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

非常感谢任何帮助!!

2 个答案:

答案 0 :(得分:1)

您可以在递归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

答案 1 :(得分:0)

每隔一段时间,有人会抱怨没有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

这满足了所述的要求,拉最后一行将使所有数量的总和相乘 - 它们都具有该值。也许聪明的人可以产生一个总计。我会把它作为一种练习(意思是我懒得自己尝试)。