逐行移动枢轴数据

时间:2013-08-09 23:57:19

标签: sql-server tsql

我需要以下数据

ID  1            2            3            4            5
--- ------------ ------------ ------------ ------------ -----------
1   NULL         NULL         NULL         NULL         Level 1
2   NULL         NULL         NULL         Level 1      Level 2
3   NULL         NULL         Level 1      Level 2      Level 3
4   NULL         Level 1      Level 2      Level 3      Level 4
5   Level 1      Level 2      Level 3      Level 4      Level 5

转换为:

ID  Level1       Level2       Level3       Level4       Level5
--- ------------ ------------ ------------ ------------ ------------
1   Level 1      NULL         NULL         NULL         NULL
2   Level 1      Level 2      NULL         NULL         NULL
3   Level 1      Level 2      Level 3      NULL         NULL
4   Level 1      Level 2      Level 3      Level 4      NULL
5   Level 1      Level 2      Level 3      Level 4      Level 5

即。在每一行中,1,2,3,4,5列的数据向左移动了将第一个非空值放入第一个位置所需的多个位置。

数据源自自引用表:

create table data (ID int not NULL, ParentID int, Name varchar(50))

通过将以下语句(包装到表值函数)应用于此表中的记录子集:

with Path(ID, ParentID, Name, Level)
as
(
    select ID, ParentID, Name, 0 from data where ID = @id
    union all
    select d.ID, d.ParentID, d.Name, p.Level-1
    from data d
        join Path p on p.ParentID = d.ID
)
select
    [1], [2], [3], [4], [5]
from
    (select 5 + Level as Level, Name from Path) s
    pivot (max(Name) for Level in ([1], [2], [3], [4], [5])) p

目前,在数据轮转后,这一转换是通过一堆case运算符实现的。但我觉得也许应该在旋转之前做一些事情(使它更优雅和/或更有效)。

理想情况下,我想在这里看到尽可能多的解决此任务的方法(在转动之前或之后的任何更改,无关紧要)。

已知级别数和常量(在这种情况下等于5)。

SQL Fiddle示例

1 个答案:

答案 0 :(得分:0)

SQL Fiddle非常有用。我通过改变功能获得了你想要的东西。这是修订后的功能:

create function ftInfo_new(@id int)
returns table as
return
    with Path(ID, ParentID, Name, Level) as
          (select ID, ParentID, Name, 0
           from data
           where ID = @id
           union all
           select d.ID, d.ParentID, d.Name, p.Level-1
           from data d join
                Path p
                on p.ParentID = d.ID
         )
    select [1], [2], [3], [4], [5]
    from (select 1 - Level as Level, Name
          from Path
         ) s
        pivot (max(Name) for Level in ([1], [2], [3], [4], [5]));

您也可以通过增加级别而不是减少级别来执行此操作:

create function ftInfo_new(@id int)
returns table as
return
    with Path(ID, ParentID, Name, Level)
    as
    (
        select ID, ParentID, Name, 1
        from data
        where ID = @id
        union all
        select d.ID, d.ParentID, d.Name, p.Level+1
        from data d join
             Path p
             on p.ParentID = d.ID
    )
    select [1], [2], [3], [4], [5]
    from (select Level as Level, Name
          from Path
         ) s
        pivot (max(Name) for Level in ([1], [2], [3], [4], [5])) p