Sql数据摘要

时间:2014-05-07 14:01:49

标签: sql sql-server tsql

我有一张这样的表:

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

如何在T-SQL中编写查询,以递归方式为每个组合Name / FromPoint上的字段FromPoint和ToPoint加入相等性? 最终期望结果的一个例子(考虑上面的数据)是:

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

3 个答案:

答案 0 :(得分:2)

使用一个递归cte,它以frompoint在自连接中没有匹配的元素开头,以便识别起始点。然后通过再次加入来释放中间结果,并仅使用那些在另一个自联接中其topoint匹配无数据的数据。

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

答案 1 :(得分:0)

不是一个完整的答案,而是一个开始 我认为这会产生结束点

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 

走回去开始思考需要一个递归的CTE
问题是你可能有像A 1 3那样的序列,所以排序不会对序列进行分组

答案 2 :(得分:0)

另一个不使用递归的选项。它使用内存中的表来编号(Num字段)不同的段。然后它编号每个段的所有成员。最后,它按名称对每个段进行分组,Num提供FromPoint的最小值和ToPoint的最大值

仅当组内没有重叠段时才会起作用。

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