2015-02-23 2 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 

Примечание: Это поможет вам 2 x 1 x 1 не 2 x 1 x 1 x 1, потому что вы используете ParentID.

+0

Удивительный! Это именно то, что я искал, но по какой-то причине не смог это понять. Просто примечание, была начальная ошибка, жалующаяся на несовместимые типы, поэтому мне пришлось жестко кодировать количество в виде десятичного числа. Спасибо вам за помощь!! – user2572833

+0

Я не думаю, что это правильный ответ. Если вы, например, меняете количества от 1 до 2, вы должны получить 2 * 2 * 2 * 2 = 16, но этот запрос вернется 8 –

+0

@GiorgiNakeuri Согласен, поэтому в нижней части моего ответа я думал об альтернативах но оставил его в покое после его принятия. –

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 перемножать - все они имеют это значение. Может быть, кто-то умный может генерировать общее количество. Я оставлю это как упражнение (это означает, что я слишком ленив, чтобы попробовать это сам).

Смежные вопросы