Использование нескольких PIVOTs JOIN и GROUP BY для расширенной генерации отчетов - PullRequest
0 голосов
/ 10 октября 2011

Я разработал систему записи расписания, которая позволяет пользователям записывать:

  • A Период времени (с 9:00 до 12:00)
  • Что они сделали за это время (DutyActivity: 1 час написания отчета, 2 часа обучения)

Когда они отправляют расписание, система также записывает их GeographyId, RoleId,CategoryId (одиночные идентификаторы) и AttributeIds (множественные идентификаторы) - это снимок пользователя на тот момент времени.

Эта записанная информация расписания может быть запрошена для отчетов.В простейшей форме система вернет список идентификаторов пользователей с суммой PeriodMinutes для каждого записанного DutyActivityId.Что будет выглядеть следующим образом:

Simple results

Однако я также хочу сгруппировать и вернуть записанные AttributeIds, записанные с каждым расписанием (в таблице TimesheetAttribute).).Однако, поскольку для каждого расписания записано несколько AttributeIds, это немного сложнее.

Моя попытка создать следующий отчет:

Complex results

Однако проблема в том, что в том, что SUM(PeriodMinutes) для каждого возвращенного DutyCategoryId теперь слишком велико.Похоже, что мой SQL включает AttributeIds для каждого расписания, что приводит к неправильным вычислениям SUM.

Я создал ZIP, содержащий SQL для схемы базы данных плюс данные вместе с SQL дляна оба запроса я сделал скриншот: Пример базы данных ZIP

Информация ниже включена в 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 Ответ

1 голос
/ 13 октября 2011

Мне удалось получить требуемый результат, отбросив второй аргумент PIVOT и AttributeId GROUP BY и вместо этого используя левое соединение для атрибутов.

Этот ответ был предоставлен visahk16 на форумах SQL 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
...