Question

I have a table like this:

Name | FromPoint | TOPoint
--------------------------
A    |   0       |    2
A    |   2       |    4
B    |   2       |    4
A    |   4       |    9
B    |   5       |    6

How can I write a query in T-SQL to recursively join on equality the fields FromPoint and ToPoint for every combination Name/FromPoint? An example (considering above data) of final desired result is:

Name  | FromPoint  | ToPoint
----------------------------
 A    |   0        |  9
 B    |   2        |  4
 B    |   5        |  6
Was it helpful?

Solution

use a recursive cte that starts with elements whose frompoint matches no topoint in a self join so as to identify the starting points. then eleminate the intermediate results by joining again and use only those data whose topoint match no frompoint in another self join.

with cte as (
    select r.name, r.frompoint, r.topoint
      from #t l
     right join 
           #t r
        on l.topoint = r.frompoint
       and l.name = r.name
     where l.name is null
     union all
    select l.name, l.frompoint, r.topoint
      from cte l
      join #t r
        on l.topoint = r.frompoint
       and l.name = r.name
)
select l.* 
  from cte l
  left join 
       #t r
    on r.name = l.name
   and r.frompoint = l.topoint
 where r.name is null

OTHER TIPS

Not a full answer but a start
I think this yields the ending points

select left.Name, left.ToPoint 
  from table left 
  left join table right 
    on left.name = right.name 
    on left.ToPoint = right.FromPoint 
 where right.FromPoint is null 

Walking back to get to the start think will require a recursive CTE
The problem is that you could have sequence inside like A 1 3 so sort would not group a sequence

Another option that doesn't use recursion. It uses a table in memory to number (Num field) the distinct segments. Then it numbers all the members of each segment. Finally it groups on each segment by Name, and Num providing the Min value of FromPoint and the Max value of ToPoint

This will work only if there are no overlapping segments within a group.

DECLARE @tbl TABLE(Num INT, Name VARCHAR(50), FromPoint INT, ToPoint INT)
INSERT INTO @tbl 
    SELECT ROW_NUMBER() OVER (ORDER BY T.Name, T.FromPoint )Num
        , T.Name, T.FromPoint, T.ToPoint
    FROM TestTable T
    WHERE NOT EXISTS(SELECT T.Name FROM TestTable T1
                          WHERE T.Name=T1.Name AND T.FromPoint=T1.ToPoint)
   UNION
    SELECT 0 Num, T2.Name, T2.FromPoint, T2.ToPoint
    FROM TestTable T2
    WHERE EXISTS(SELECT T3.Name FROM TestTable T3 
                 WHERE T2.Name=T3.Name AND T2.FromPoint=T3.ToPoint)

SELECT MyTable.Name, MIN(MyTable.FromPoint)FromPoint, MAX(MyTable.ToPoint)ToPoint
FROM
 (SELECT CASE WHEN T.Num=0 THEN 
    (SELECT TOP 1 TMP.Num FROM @tbl TMP WHERE TMP.Name=T.Name 
            AND T.FromPoint>TMP.FromPoint AND TMP.Num>0
     ORDER BY T.FromPoint-TMP.FromPoint
               )
    ELSE T.Num END Num
   ,T.Name, T.FromPoint, T.ToPoint FROM
@tbl T)MyTable
GROUP BY MyTable.Name, MyTable.Num
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top