从一列中提取分层数据

时间:2014-02-19 13:42:38

标签: tsql sql-server-2012 hierarchical-data

我有以下示例数据:

enter image description here

它基本上显示以下层次结构:

enter image description here

我应该从中得到所有(S)挞(E)和这样的对(顺序并不重要):

enter image description here

我的解决方案是推送“Source”表变量中的所有值:

  1. 选择所有连续性(S)挞(E)和配对
  2. 将它们插入“目标”表变量
  3. 从“来源”表格变量
  4. 中删除它们
  5. 如果“Source”表变量不为空,则执行步骤
  6. 我的问题是有人想出替代解决方案吗?在我的实际情况中,我有更多行,我担心删除和插入表变量。

    以下脚本生成示例数据:

    DECLARE @DataSource TABLE
    (
        [ID] TINYINT
       ,[Type] CHAR(1)
    )
    
    INSERT INTO @DataSource ([ID], [Type])
    VALUES (3,'S')
          ,(6,'E')
          ,(7,'S')
          ,(10,'S')
          ,(13,'E')
          ,(14,'E')
          ,(15,'S')
          ,(16,'S')
          ,(17,'S')
          ,(19,'S')
          ,(20,'S')
          ,(26,'E')
          ,(27,'E')
          ,(28,'E')
          ,(29,'E')
          ,(30,'E')
          ,(31,'S')
          ,(32,'S')
          ,(35,'E')
          ,(36,'S')
          ,(38,'E')
          ,(39,'S')
          ,(40,'S')
          ,(44,'E')
          ,(45,'E')
          ,(46,'E')
    

1 个答案:

答案 0 :(得分:1)

这有点复杂,但试试这个:

;with a as
(
  select [ID], [Type], row_number() over (order by ID) rn from @DataSource
), b as
(
  select [ID], [Type], rn, cast(1 as int) lvl from a where rn = 1
  union all
  select a.[ID], a.[Type],a.rn, case when a.[Type] = 'S' then 1 when a.[Type] = 'E' then -1 else 0 end + lvl 
  from a
  join b on a.rn = b.rn + 1
), 
c as
(
  select [ID], [Type], row_number() over (partition by [type] order by lvl,rn) grp
  from b
)
select c1.id S, c2.id E from c c1
join c c2
on c1.grp = c2.grp
where c1.[type] = 'S' and c2.[type] = 'E'
order by c1.id
option( maxrecursion 0) 

结果:

S   E
3   6
7   14
10  13
15  30
16  29
17  28
19  27
20  26
31  46
32  35
36  38
39  45
40  44
编辑:因为您使用的是sqlserver 2012,脚本可以简化,我还添加了性能改进。我希望这适用于你的情况。脚本现在假设'S'总是在'E'之前。

;with a as
(
  select [ID], [Type], 
  sum(case when [type]='S' then 1 when [type]='E' then -1 end)over(order by id) lvl
  from @DataSource
), b as
(
  select [ID], [Type], 
  row_number() over (partition by [type] order by lvl,id) grp
  from a
)
select min(id) S, max(id) E 
from b
group by grp
order by s