2015-02-23 45 views
0

我找到位于一个非常有用的文章: Simplest way to do a recursive self-join in SQL Server?琛对递归型自加入

在这个例子中假设有一个叫存储,看起来像这样的整数“数量”的另一列:

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 

任何帮助是极大的赞赏!

回答

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 

注:这是因为你使用ParentID让你2 x 1 x 12 x 1 x 1 x 1

+0

太棒了!这正是我正在寻找的东西,但由于某种原因无法想出它。只是一个说明,有一个初始错误抱怨不兼容的类型,所以我不得不硬编码数量作为一个小数。感谢您的帮助!! – user2572833 2015-02-23 18:56:51

+0

我不认为这是正确的答案。例如,如果您将数量从1更改为2,则应该得到2 * 2 * 2 * 2 = 16,但此查询将返回8 – 2015-02-23 19:25:37

+0

@GiorgiNakeuri同意,因此我在回答底部的注释中,我正在考虑替代方法但在被接受之后让它一个人待着。 – 2015-02-23 20:05:05

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 

这满足了要求,指出,拉动了最后一排将有共计所有QTYs的相乘 - 它们都有价值。也许有人聪明可以产生一个运行总数。我会把它作为一个练习(意味着我懒得自己尝试)。