属于层次结构

时间:2015-06-13 20:16:25

标签: sql sql-server sql-server-2008 hierarchy

我的问题与this one类似,但在我的理解中却有所不同。

我有三张桌子:

  1. Units ([UnitID] int, [UnitParentID] int)
  2. Students ([StudentID] int, [UnitID] int)
  3. Events ([EventID] int, [EventTypeID] int, [StudentID] int)
  4. Students属于单位,单位以层次结构堆叠(树形式 - 每个孩子一个父母),每个学生可以有不同类型的事件。

    我需要总结每个用户每种类型的事件数,然后汇总一个单元中的所有用户,然后通过层次结构聚合,直到我到达所有单位的母亲。

    结果应该是这样的: result example

    我的工具是SQL Server 2008和Report Builder 3。 为了好玩,我提供了一个SQL fiddle样本数据。

2 个答案:

答案 0 :(得分:3)

使用此查询:

;WITH CTE(Id, ParentId, cLevel, Title, ord) AS (
    SELECT 
        u.UnitID, u.UnitParentID, 1, 
        CAST('Unit ' + CAST(ROW_NUMBER() OVER (ORDER BY u.UnitID) AS varchar(3)) AS varchar(max)),
        CAST(RIGHT('000' + CAST(ROW_NUMBER() OVER (ORDER BY u.UnitID) AS varchar(3)), 3) AS varchar(max))
    FROM 
        dbo.Units u
    WHERE 
        u.UnitParentID IS NULL
    UNION ALL
    SELECT
        u.UnitID, u.UnitParentID, c.cLevel + 1, 
        c.Title + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY c.cLevel ORDER BY c.Id) AS varchar(3)),
        c.ord + RIGHT('000' + CAST(ROW_NUMBER() OVER (ORDER BY u.UnitID) AS varchar(3)), 3)
    FROM
        dbo.Units u
        JOIN
        CTE c ON c.Id = u.UnitParentID
    WHERE 
        u.UnitParentID IS NOT NULL
), Units AS (
SELECT 
    u.Id, u.ParentId, u.cLevel, u.Title, u.ord,
    SUM(CASE WHEN e.EventTypeId = 1 THEN 1 ELSE 0 END) AS EventA,
    SUM(CASE WHEN e.EventTypeId = 2 THEN 1 ELSE 0 END) AS EventB,
    SUM(CASE WHEN e.EventTypeId = 3 THEN 1 ELSE 0 END) AS EventC,
    SUM(CASE WHEN e.EventTypeId = 4 THEN 1 ELSE 0 END) AS EventD
FROM 
    CTE u
    LEFT JOIN
    dbo.Students s ON u.Id = s.UnitId
    LEFT JOIN
    dbo.[Events] e ON s.StudentId = e.StudentId
GROUP BY
    u.Id, u.ParentId, u.cLevel, u.Title, u.ord
), addStudents AS (
SELECT *
FROM Units
UNION ALL
SELECT 
    s.StudentId, u.Id, u.cLevel + 1,
    'Student ' + CAST(s.StudentId AS varchar(3)),
    u.ord + RIGHT('000' + CAST(s.StudentId AS varchar(3)), 0),
    SUM(CASE WHEN e.EventTypeId = 1 THEN 1 ELSE 0 END),
    SUM(CASE WHEN e.EventTypeId = 2 THEN 1 ELSE 0 END),
    SUM(CASE WHEN e.EventTypeId = 3 THEN 1 ELSE 0 END),
    SUM(CASE WHEN e.EventTypeId = 4 THEN 1 ELSE 0 END)
FROM Units u
    JOIN
    dbo.Students s ON u.Id = s.UnitId
    LEFT JOIN
    dbo.[Events] e ON s.StudentId = e.StudentId
GROUP BY
    s.StudentID, u.ID, u.cLevel, u.ord
)
SELECT --TOP(10)
    REPLICATE(' ', cLevel) + Title As Title, 
    EventA, EventB, EventC, EventD
FROM
    addStudents 
ORDER BY
    ord

为此:

Title            | EventA | EventB  | EventC | EventD
-----------------+--------+---------+--------+--------
 Unit 1          | 0      | 1       | 0      | 0
  Student 6      | 0      | 1       | 0      | 0
  Unit 1.1       | 0      | 0       | 0      | 1
   Student 21    | 0      | 0       | 0      | 1
   Student 33    | 0      | 0       | 0      | 0
   Unit 1.1.1    | 0      | 0       | 0      | 0
    Student 23   | 0      | 0       | 0      | 0
    Unit 1.1.1.1 | 3      | 2       | 3      | 0
     Student 10  | 0      | 0       | 0      | 0
     Student 17  | 1      | 0       | 0      | 0
...

SQL Fiddle Demo

答案 1 :(得分:1)

您是否还需要对层次结构进行排序/可视化?至少这将计算总和,但数据的顺序非常随机:)

;with CTE as (
  select S.StudentId as UnitID, S.UnitId as UnitParentID,
    S.StudentID, 'Student' as Type
  from Students S
union all
  select U.UnitId, U.UnitParentId, 
    CTE.StudentId as StudentID, 'Unit   ' as Type
  from
    Units U
    join CTE
      on U.UnitId = CTE.UnitParentId
)
select C.Type + ' ' + convert(varchar, C.UnitId), 
  sum(case when EventTypeId = 1 then 1 else 0 end) as E1,
  sum(case when EventTypeId = 2 then 1 else 0 end) as E2,
  sum(case when EventTypeId = 3 then 1 else 0 end) as E3,
  sum(case when EventTypeId = 4 then 1 else 0 end) as E4
from 
  CTE C
  left outer join events E on C.StudentId = E.StudentId
group by
  C.Type, C.UnitId

SQL Fiddle

如果您还需要层次结构,那么您可能需要添加一些额外的CTE来自上而下使用@ shA.t这样的编号。这会为每个学生单独收集层次结构,因此无法以简单的方式添加级别编号。