繁体   English   中英

递归自联接的总和

[英]Sum on a Recursive Self-Join

我在以下位置找到了一篇非常有用的文章: 在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总数相乘即可,它们都具有该值。 也许某个聪明的人可以产生一个连续的总数。 我将其保留为练习(这意味着我懒得自己尝试一下)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM