使用多个PIVOT JOIN和GROUP BY来生成高级报告

时间:2011-10-10 14:55:27

标签: sql join group-by reporting pivot

我开发了一个时间表记录系统,允许用户记录:

  • 一段时间(9:00至12:00)
  • 他们在那段时间做了什么(DutyActivity:1小时撰写报告,2小时培训)

当他们提交时间表时,系统还会记录他们的GeographyId,RoleId,CategoryId(单个ID)和AttributeIds(多个ID) - 这是用户在该时间点的快照。

然后可以查询记录的时间表信息以获取报告。在最简单的形式中,系统将返回一个UserIds列表,其中每个记录的PeriodMinutes的SUM为DutyActivityId。看起来如下:

Simple results

然而,我还想做的是分组并返回每个时间表记录的记录AttributeIds(在TimesheetAttribute表中)。但是,因为每个时间表记录了多个AttributeIds,所以它更复杂一些。

我的尝试创建了以下报告:

Complex results

但问题是,每个SUM(PeriodMinutes)返回的DutyCategoryId现在太高了。我的SQL似乎为每个时间表包含AttributeIds导致SUM计算错误。

我已经创建了一个包含数据库架构和数据的SQL的ZIP,以及我在此处截图的两个查询的SQL:ZIP Timesheet example database

以下信息包含在ZIP中,但我在此处将它们链接起来以方便访问:

Database diagram

报告时间表,没有属性分组

SELECT
*
FROM
(
SELECT
T.UserId,
T.RoleId,T.GeographyId,T.CategoryId,
TDA.DutyActivityId AS TypeId,
SUM(TDA.PeriodMinutes) AS Total
FROM 
Timesheet AS T

LEFT JOIN 
TimesheetDutyActivity AS TDA ON
TDA.TimesheetId = T.TimesheetId

GROUP BY
T.UserId,
T.RoleId,T.GeographyId,T.CategoryId,
TDA.DutyActivityId
) AS SourceTable

/* PIVOT against the known DutyActivityIds */
PIVOT
(
SUM(Total)
FOR TypeId IN ([1],[2],[3],[4],[5])
)
AS PivotType

ORDER BY UserId ASC

报告时间表,尝试属性分组

SELECT
*
FROM
(
SELECT
T.UserId,
T.RoleId,T.GeographyId,T.CategoryId,
TA.AttributeId * -1 AS AttributeId, /* Multiply AttributeId by -1 in order to create negative Ids, so that two PIVOT operations can be used */
TDA.DutyActivityId AS TypeId,
SUM(TDA.PeriodMinutes) AS Total

FROM 
Timesheet AS T

LEFT JOIN 
TimesheetAttribute AS TA ON
TA.TimesheetId = T.TimesheetId

LEFT JOIN 
TimesheetDutyActivity AS TDA ON
TDA.TimesheetId = T.TimesheetId

GROUP BY
T.UserId,
AttributeId,
T.RoleId,T.GeographyId,T.CategoryId,
TDA.DutyActivityId
) AS SourceTable

/* PIVOT against the known DutyActivityIds */
PIVOT
(
SUM(Total)
FOR TypeId IN ([1],[2],[3],[4],[5])
)
AS PivotType

/* Also PIVOT against the known AttributeIds */
PIVOT
(
SUM(AttributeId)
FOR AttributeId IN ([-1],[-2],[-3],[-4],[-5])
)
AS PivotAttribute

ORDER BY UserId ASC

1 个答案:

答案 0 :(得分:1)

我设法通过删除第二个PIVOT和AttributeId GROUP BY参数并在属性上使用LEFT JOIN来获得所需的结果。

此答案由visahk16SQL Team论坛上提供:

SELECT
    *
    FROM
    (
    SELECT
    T.UserId,
    T.RoleId,T.GeographyId,T.CategoryId,
    TA.[-1],TA.[-2],TA.[-3],TA.[-4],TA.[-5],
    TDA.DutyActivityId AS TypeId,
    SUM(TDA.PeriodMinutes) AS Total

    FROM 
    Timesheet AS T

    LEFT JOIN 
    (SELECT TimesheetId,
     SUM(CASE WHEN AttributeId ='1' THEN -1 ELSE 0 END) AS [-1],
     SUM(CASE WHEN AttributeId ='2' THEN -1 ELSE 0 END) AS [-2],
...
     SUM(CASE WHEN AttributeId ='5' THEN -1 ELSE 0 END) AS [-5] 
     FROM TimesheetAttribute 
     GROUP BY TimesheetId 
     )AS TA ON
    TA.TimesheetId = T.TimesheetId

    LEFT JOIN 
    TimesheetDutyActivity AS TDA ON
    TDA.TimesheetId = T.TimesheetId

    GROUP BY
    T.UserId,
    AttributeId,
    T.RoleId,T.GeographyId,T.CategoryId,
    TDA.DutyActivityId
    ) AS SourceTable

    /* PIVOT against the known DutyActivityIds */
    PIVOT
    (
    SUM(Total)
    FOR TypeId IN ([1],[2],[3],[4],[5])
    )
    AS PivotType

    ORDER BY UserId ASC