没有聚合的SQL数据透视表

时间:2014-05-02 17:15:36

标签: sql sql-server pivot

更新

我修改了SQL Fiddle,使部门名称更能反映我想要达到的目标。如果你看小提琴,有3个选择语句。

  1. 从数据
  2. 按正确顺序列出部门
  3. 我尝试转向的结果
  4. 假选择以显示我正在尝试进入
  5. 在我的数据透视尝试的结果中,第二行显示为departmentLevel1的null,而departmentLevel3不应该在此行中。我尝试了row_number和分区的各种组合,但我似乎无法弄清楚这一点。 非常沮丧!

    这是我最新的小提琴http://sqlfiddle.com/#!3/175af/40

    在您决定关闭之前 请阅读此问题,然后阅读重复的问题。选址的问题更为简单。我的问题不仅仅是询问旋转,而是对枢轴结果进行分组,并进行更多的旋转启动和停止时间。我认为只看标题。如果您不想阅读整个问题,但不要认为它与其他具有类似标题的问题相同。

    我意识到我必须有一个聚合,所以我尝试使用max,但我真的只是想以更表格的方式显示这些信息,所以我可以将它加入另一个数据集。

    以下是起始数据:

    select  departmentID, departmentParentID, departmentName, departmentGroupSortBy, departmentLevel, sortBy
    from    vDepartmentList
    where   regionID = 3
    order by departmentGroupSortBy, departmentLevel, sortBy
    
    departmentID    departmentParentID  departmentName  departmentGroupSortBy   departmentLevel sortBy
    ---------------------------------------------------------------------------------------------------
    111                                 neth test dept  1                       1                1
    115             111                 test sub1       1                       2               1
    112                                 test2           2                       1                2
    113             112                 new sub2        2                       2               1
    114             112                 new sub 3a      2                       2                 2
    116             114                 should L3       2                       3                 1
    

    如果我运行此查询:

    select  departmentParentID, [1] as departmentLevel1, [2] as departmentLevel2, [3] as departmentLevel3
    from    (
        select  departmentParentID, departmentLevel, departmentName
        from    vDepartmentList
        where   regionID = 3
        ) p
    pivot (
        max(departmentName)
        for departmentLevel in ([1],[2],[3])
        ) as  pvt
    order by departmentParentID
    

    我得到了这个结果:

    departmentParentID  departmentLevel1    departmentLevel2    departmentLevel3
    ----------------------------------------------------------------------------
                        test2       
    111                                     test sub1   
    112                                     new sub2    
    114                                                          should L3
    

    但我想要得到的是:

    departmentParentID  departmentLevel1    departmentLevel2    departmentLevel3
    ----------------------------------------------------------------------------
    111                 neth test dept      test sub1   
    112                 test2               new sub2    
    112                 test2               new sub 3a          should L3
    

    有没有人建议我哪里出错了?

3 个答案:

答案 0 :(得分:3)

由于您需要返回层次结构数据结构的3个级别,因此使用JOIN而不是使用PIVOT可能要容易得多。您将从返回父行开始:

select p.departmentName
from dbo.department p
where p.departmentParentID is null;

这将为您提供所有顶级行。然后,您开始为所需的每个附加级别添加联接,在您需要总共三个级别的情况下,您将添加两个联接。最终查询如下:

select p.departmentName department1,
    c.departmentName department2,
    gc.departmentName department3
from dbo.department p         -- parent level
left join dbo.department c    -- child level 
    on p.departmentID = c.departmentParentID
left join dbo.department gc   -- grandchild level
    on c.departmentID = gc.departmentParentID
where p.departmentParentID is null;

SQL Fiddle with Demo

似乎使用JOIN而不是使用PIVOT更容易获得结果。这使用源数据而不是您创建的递归视图。这给出了以下结果:

| DEPARTMENT1 | DEPARTMENT2 |  DEPARTMENT3 |
|-------------|-------------|--------------|
|     depart1 |     d1 sub1 |       (null) |
|     depart2 |      d2 sub |       (null) |
|     depart2 |     d2 sub2 | d2s2 subSub1 |

如果您想使用递归查询来获取结果,那么您可以稍微更改当前视图以返回3列名称而不是级别数字:

;with cte as
(
    select departmentID, 
        departmentParentID,  
        departmentName as Department1,
        cast(null as varchar(100)) Department2,
        cast(null as varchar(100)) Department3,
        1 as Level
    from dbo.department
    where departmentParentID is null
    union all
    select d.departmentID, 
        d.departmentParentID,
        Department1,
        case when Level + 1 = 2 then d.departmentName else Department2 end,
        case when Level + 1 = 3 then d.departmentName else Department3 end,
        Level + 1
    from dbo.department d
    inner join cte h
        on d.departmentParentID = h.departmentID
)
select *
from cte;

SQL Fiddle with Demo。然后,您可以使用WHERE子句进行一些过滤,以返回具有您需要的所有部门值的行。

答案 1 :(得分:1)

我根据你的视图sql创建了下面的sql。你几乎得到了结果。

我使用@temp表来删除order by子句。可能你可以删除实现中的@temp表。

请尝试以下sql:

declare @temp table
(
  id int identity,
  departmentLevel1 int,
  departmentLevel2 int,
  departmentLevel3 int,
  xRow int
)

insert into @temp 
select 
    d.lvl1, d.lvl2, d.lvl3
    ,Rrow
from
(
select 
    a.lvl1, a.lvl2, a.lvl3
    ,row_number() over(partition by a.lvl1,a.lvl2 order by a.lvl1,a.lvl2) as Rrow
    ,departmentGroupSortby, departmentlevel, sortby
from 
    vDepartmentList a
) d
where (d.lvl2 is not null) 
order by departmentGroupSortby, departmentlevel, sortby
;

select
    c.departmentLevel1 as departmentParentID
    ,Case
        when c.departmentLevel1 = d.departmentid then d.DepartmentName
        else 
            null
     end as DepartmentLevel1
    ,Case
        when c.departmentLevel2 = e.departmentid then e.DepartmentName
        else 
            null
     end as DepartmentLevel2
    ,Case
        when c.departmentLevel3 = f.departmentid then f.DepartmentName
        else 
            null
     end as DepartmentLevel3
    --,d.departmentId   ,e.departmentid ,f.departmentid
from
(
select 
    a.id, a.departmentLevel1,a.departmentLevel2,a.departmentLevel3
    ,a.xRow
from @temp a
inner join
(
select 
    cast(departmentLevel1 as nvarchar(5)) + cast(departmentLevel2 as nvarchar(5)) as xrow, count(cast(departmentLevel1 as nvarchar(5)) + cast(departmentLevel2 as nvarchar(5))) as xcount
from @temp
group by cast(departmentLevel1 as nvarchar(5)) + cast(departmentLevel2 as nvarchar(5))
) b on cast(a.departmentLevel1 as nvarchar(5)) + cast(a.departmentLevel2 as nvarchar(5)) = b.xrow and a.xRow = b.xcount
) c
left join department d on c.departmentLevel1 = d.departmentId
left join department e on c.departmentLevel2 = e.departmentid
left join department f on c.departmentLevel3 = f.departmentid



结果

departmentParentID DepartmentLevel1 DepartmentLevel2 DepartmentLevel3
------------------ ---------------- ---------------- ----------------
111                depart1          d1 sub1          NULL
112                depart2          d2 sub           NULL
112                depart2          d2 sub2          d2s2 subSub1

希望这是帮助

答案 2 :(得分:0)

透视就像分组一样。您需要原始源中的列进行分组。在这种情况下,你没有它,并且他不知道'测试sub1'以任何方式与“测试部门”相关联。我们这里需要的是建立层次结构的根。我们可以使用一个小的递归CTE(用vDepartmentList替换#t):

;with x as (
    select *, departmentID as root
    from #t
    where departmentParentID is null
    union all
    select #t.*, x.root
    from #t
    inner join x on #t.departmentParentID = x.departmentID
)
select * 
from x

所以现在我们也有一个根也有另一个问题:我们只有两个根,但你想在结果中有三行。枢轴操作员将基本上分组根列,并将处理新的sub2'新的sub 3a'和'应该L3'因为所有人都属于' test2',并生成一行,其中包含这些值的最大值。

应该有一种区分方法,但我无法在您的数据中看到它。所以,看起来,你运气不好。