开发者

Recursive Query on a self referential table (not hierarchical)

I am creating a state chart of sorts with the data being stored in a simple self referencing table (JobPath)

JobId - ParentJobId

I was using a standard SQL CTE to get the data out which was working perfectly until I ended up with the following data

JobId - ParentId
  1        2
  2        3
  3        4
  4        2

Now as you can see Job 4 links to Job 2 which goes to Job 3 and th开发者_C百科en to Job 4 and so on.

Is there any way I can tell my query not to pull out data it already has?


Here is my current query

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 
)

-- Statement that executes the CTE

SELECT * FROM JobPathTemp


If you are not dealing with a large number of entries, the following solution might be suitable. The idea is to build the complete "id path" for each row and make sure the "current id" (in the recursive part) is not already in the path being processed:

(I removed the join to jobpath for testing purposes but the basic pattern should be the same)

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
;


This solution doesn't work, SQL Server doesn't support using UNION to join together the recursive term. Since you can't refer to the the recursion except as the join, tbh I don't see any alternative to using a stored function...


You didn't post your query... but I tried (in postgres, which works in much the same way) and if you use "UNION" (not "UNION ALL") in the recursive term, then it should automatically remove duplicate rows:

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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜