Рекурсивный запрос к самореферентной таблице (не иерархической) - PullRequest
2 голосов
/ 07 января 2011

Я создаю диаграмму состояний с сохранением данных в простой самоссылающейся таблице (JobPath)

JobId - ParentJobId

Я использовал стандартный SQL CTE для получения данных, который работал отлично, пока я не получил следующие данные

JobId - ParentId
  1        2
  2        3
  3        4
  4        2

Теперь, как вы можете видеть, Задание 4 связано с Заданием 2, которое переходит к Заданию 3, а затем к Заданию 4 и т. Д.

Можно ли как-то сказать, что мой запрос не должен извлекать данные, которые у него уже есть?


Вот мой текущий запрос

WITH JobPathTemp (JobId, ParentId, Level)
AS
(
-- Anchor member definition
    SELECT j.JobId, jp.ParentJobId, 1 AS Level
    FROM Job AS j
    LEFT OUTER JOIN dbo.JobPath AS jp
        ON j.JobId = jp.JobId
    where j.JobId=1516
    UNION ALL
-- Recursive member definition
    SELECT  j.JobId, jp.ParentJobId, Level + 1
    FROM dbo.Job as j
    INNER JOIN dbo.JobPath AS jp
        ON j.JobId = jp.JobId
    INNER JOIN JobPathTemp AS jpt
        ON jpt.ParentId = jp.JobId
      WHERE jp.ParentJobId <> jpt.JobId 
)

- Оператор, который выполняет CTE

SELECT * FROM JobPathTemp

Ответы [ 2 ]

3 голосов
/ 07 января 2011

Если вы не имеете дело с большим количеством записей, может подойти следующее решение. Идея состоит в том, чтобы создать полный «путь идентификатора» для каждой строки и убедиться, что «текущий идентификатор» (в рекурсивной части) еще не находится в обрабатываемом пути:

(я удалил объединение с рабочим путем для целей тестирования, но базовый шаблон должен быть таким же)

WITH JobPathTemp (JobId, ParentId, Level, id_path)
AS
(
  SELECT jobid, 
         parentid, 
         1 as level, 
         '|' + cast(jobid as varchar(max)) as id_path
  FROM job
  WHERE jobid = 1

  UNION ALL

  SELECT  j.JobId, 
          j.parentid, 
          Level + 1, 
          jpt.id_path + '|' + cast(j.jobid as varchar(max))
  FROM Job as j
    INNER JOIN JobPathTemp AS jpt ON j.jobid = jpt.parentid 
                                     AND charindex('|' + cast(j.jobid as varchar), jpt.id_path) = 0
)
SELECT *
FROM JobPathTemp
;
0 голосов
/ 07 января 2011

Это решение не работает, SQL Server не поддерживает использование UNION для объединения рекурсивного термина.Поскольку вы не можете ссылаться на рекурсию, кроме как на соединение, я не вижу альтернативы использованию хранимой функции ...


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

with /*recursive*/ jobs as
 (select jobpath.jobid, jobpath.parentjobid from jobpath where jobid = 1
  union
  select jobpath.jobid, jobpath.parentjobid
  from jobpath
       join jobs on jobs.parentjobid = jobpath.jobid
 )
select jobpath.* from jobpath join jobs on jobpath.jobid = jobs.jobid;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...