0

我需要以下数据

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 小提琴示例

4

1 回答 1

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
于 2013-08-10T20:42:28.170 回答