2013-09-13 6 views
0

У меня есть таблица, которая связывает работу вместе:Как решить эту проблему с помощью CTE?

JobToJob 
(
    JobToJobId int 
    SourceJobId int 
    DestinationJobId int 
) 

Задание может иметь несколько рабочих мест Направление (т.е. более 1 JobToJob записи), но только один источник задания. Таким образом, создается древовидная структура. Корневая запись определяется как та, которая не имеет записей DestinationJobId на любой другой записи.

Требование, которое у меня есть, состоит в том, чтобы получить все дерево для предоставленного идентификатора задания. Я разделить это на две части:

  1. Найдите корень работу для данного задания идентификатора
  2. извлекать все листья для ид корня работы.

У меня есть попытка попробовать это с использованием рекурсивного КТВ, но я никуда не денусь. Я знаю, что я мог бы сделать это, используя хранимую процедуру, но я стараюсь избегать этого, поскольку они склонны замедлять работу.

У кого-нибудь с более рекурсивным опытом CTE, чем у меня, есть предложения относительно наилучшего подхода к этому?

Приветствия,

Роб

+0

Если задание может иметь только одно задание источника, то я думаю, что лучший дизайн базы данных будет создавать поле 'SourceJobID' в таблице' Job'. затем создайте два CTE (один для получения всех исходных заданий (вверх)) и второй форматирующий все назначения (вниз) после просто UNION, что два CTE ... – Fabio

+0

К сожалению, это устаревшая система, и это не вариант в этом случай ... –

ответ

0

Надеюсь, у вас есть таблица рабочих мест.

declare @JobId int 
;with getAscendants(job, parent, inverseDepth) 
as 
(
    select jj.DestinationJobId, jj.SourceJobId, 1 
    from JobToJob jj 
    where jj.DestinationJobId = @JobId 

    union all 

    select jj.DestinationJobId, jj.SourceJobId, inverseDepth + 1 
    from getAscendants 
    join JobToJob jj on jj.DestinationJobId = getAscendants.parent 
) 
,rootFinder(job) 
as 
(
    select j.JobId 
    from Jobs j 
    where j.JobId = coalesce 
    (
    (
     select top 1 parent from getAscendants order by inverseDepth desc 
    ) 
    , @JobId 
) 
) 
,getDescendants(job, parent) 
as 
(
    select j.JobId, null 
    from Jobs j 
    cross apply rootFinder 
    where j.JobId = rootFinder.job 

    union all 

    select jj.DestinationJobId, jj.SourceJobId 
    from getDescendants 
    join JobToJob jj on jj.SourceJobId = getDescendants.job 
) 
select * from getDescendants 
+0

Этот ответ был настолько точным, что мне не нужно его каким-либо образом менять - спасибо вам большое! О, и у меня есть таблица рабочих мест ...! –

0

Вы используете термин «листья», что означает рабочие места, которые не имеют места назначения (в отличие от промежуточных узлов в дереве).

Вот один из подходов. Начните со всех листьев, затем поднимитесь по дереву, прикрепляя все узлы, на которых они находятся. Затем выберите те, которые относятся к интересующей вас работе:

with cte as (
     select DestinationJobId as JobId, DestinationJobId as parent, 1 as level 
     from jobs2jobs jj 
     where DestinationJobId not in (select SourceJobId from jobs2jobs) 
     union all 
     select cte.JobId, jj.SourceJobId, level + 1 
     from cte 
      jobs2jobs jj 
      on cte.Parent = jj.DestinationJobId 
    ) 
select * 
from cte 
where parent = @YourJobId; 
Смежные вопросы