2011-03-21 23 views
1

Я пытаюсь написать запрос, используя эти четыре упрощенные таблицы:рекурсивного запроса и Count (SQL Server)

Организация
(рк) OrganizationID
OrganizationName
(Ф.К.) ParentOrganizationID

Персонал
(pk) ПерсоналID
(fk) OrganizationID
Имя

Событие
(рк) событие с кодом
EventName

EventLog
(рк) PersonnelID
(рк) событие с кодом
TimeOfParticipation

Я хочу, чтобы создать запрос, который принимает идентификатор события и идентификатор организации как параметр er и возвращает таблицу, которая возвращает все имя организации, общее количество в организации и детских организациях, а также общее количество участников мероприятия для организации и ее детей. Примером может быть возвращение:

OrganizationName | TotalNumberInOrganization | TotalParticipatingInEvent 
TopOrganization |   200    |   150  
SecondTier1  |   150    |   100 
    Tier1Child  |   50    |    50 
    Tier1Child2  |   50    |    25 
SecondTier2  |   25    |    25 

Верхняя организация является суммой всех своих детей, SecondTier1 и SecondTier2, и само по себе. SecondTier1 - это сумма всех его детей, Teir1Child и Tier1Child2, и сама. Это будет продолжаться при расчете всех детей и итогов.

Я знаю, как вернуть только одну запись с использованием рекурсивного CTE, например, всего для топ-организации, но я не уверен, как получить итоговые данные для всех организаций и их детей. Любая помощь будет оценена по достоинству.

В соответствии с запрошенной здесь процедурой, которую я использую для возврата одной строки об организации.

По какой-то причине, если я добавлю «U» в UNION, это вызывает сетевую ошибку и не позволит мне ее редактировать.

@OrganizationID uniqueidentifier 
@EventID uniqueidentifier 

WITH OrganizationList(OrganizationID) AS 
    (SELECT Organization.OrganizationID 
    FROM Organization 
    WHERE OrganizationID = @OrganizationID 
    NION ALL 
    SELECT Organization.OrganizationID 
    FROM Organization 
    INNER JOIN OrganizationList ON Organization.ParentOrganizationID = OrganizationList.OrganizationID) 

SELECT OrganizationAbbreviation, 

     (SELECT COUNT(*) 
     FROM Personnel 
     WHERE Personnel.OrganizationID IN (SELECT OrganizationID FROM OrganizationList)) 
     AS OrganizationTotal, 

     (SELECT COUNT(*) 
     FROM Personnel 
     INNER JOIN EventLog ON EventLog.PersonnelID = Personnel.PersonnelID 
     WHERE Personnel.OrganizationID IN (SELECT OrganizationID FROM OrganizationList) 
       AND EventLog.EventID = @EventID) 
     AS TotalPresent 
FROM Organization 
WHERE OrganizationID = @OrganizationID 
+0

Проблема заключается в том, рекурсивные CTE в SQL Server имеют некоторые ограничения. В частности, рекурсивной части не разрешается содержать группировку и, следовательно, агрегаты. По этой причине мне бы очень хотелось узнать, что может быть вашим решением для одной записи, особенно на более высоком уровне. Не могли бы вы разместить его? Кто-то здесь может иметь хорошее представление о том, как разработать его в полное решение для вашего дела. –

ответ

2

Я думаю, что это будет работать для вас:

WITH OrganizationTree (RootOrganizationID, OrganizationID) 
AS 
(
--Anchor 
    SELECT O.OrganizationID, O.OrganizationID 
    FROM Organization O 
    UNION ALL 
--Recurse 
    SELECT T.RootOrganizationID, O.OrganizationID 
    FROM OrganizationTree T 
    JOIN Organization O 
     ON O.ParentOrganizationId = T.OrganizationID 
) 
--execute 
SELECT P.OrganizationName, 
     SUM(ISNULL(PPL.NumberInOrganization, 0)) AS TotalNumberInOrganization, 
     SUM(ISNULL(EVT.NumberParticipatingInEvent, 0)) AS TotalNumberParticipatingInEvent 
FROM OrganizationTree T 
JOIN Organization P 
     ON T.RootOrganizationID = P.OrganizationID 
LEFT 
JOIN  
(
     SELECT P.OrganizationID, 
       COUNT(*) AS NumberInOrganization 
     FROM Personnel P 
     GROUP BY P.OrganizationID 
) PPL 
     ON PPL.OrganizationID = T.OrganizationID 
LEFT 
JOIN 
(
     SELECT P.OrganizationID, 
       COUNT(*) AS NumberParticipatingInEvent 
     FROM EventLog EL 
     JOIN Personnel P 
       ON EL.PersonnelID = P.PersonnelID 
     GROUP BY P.OrganizationID 
) EVT 
     ON EVT.OrganizationID = T.OrganizationID 
GROUP BY T.RootOrganizationID, P.OrganizationName 

Если вам нужно иметь отступ, как в вашем примере вывода, то это должно работать:

WITH OrganizationTree (RootOrganizationID, OrganizationID) 
AS 
(
--Anchor 
    SELECT O.OrganizationID, O.OrganizationID 
    FROM Organization O 
    UNION ALL 
--Recurse 
    SELECT T.RootOrganizationID, O.OrganizationID 
    FROM OrganizationTree T 
    JOIN Organization O 
     ON O.ParentOrganizationId = T.OrganizationID 
) 
--execute 
SELECT SPACE(L.OrganizationLevel) + P.OrganizationName AS FormattedOrganizationName, 
     P.OrganizationName, 
     SUM(ISNULL(PPL.NumberInOrganization, 0)) AS TotalNumberInOrganization, 
     SUM(ISNULL(EVT.NumberParticipatingInEvent, 0)) AS TotalNumberParticipatingInEvent 
FROM OrganizationTree T 
JOIN  
(
     SELECT L.OrganizationID, 
       (COUNT(*) - 1) AS OrganizationLevel 
     FROM OrganizationTree L 
     GROUP BY L.OrganizationID 
) L 
    ON T.RootOrganizationID = L.OrganizationID 
JOIN Organization P 
     ON T.RootOrganizationID = P.OrganizationID 
LEFT 
JOIN  
(
     SELECT P.OrganizationID, 
       COUNT(*) AS NumberInOrganization 
     FROM Personnel P 
     GROUP BY P.OrganizationID 
) PPL 
     ON PPL.OrganizationID = T.OrganizationID 
LEFT 
JOIN 
(
     SELECT P.OrganizationID, 
       COUNT(*) AS NumberParticipatingInEvent 
     FROM EventLog EL 
     JOIN Personnel P 
       ON EL.PersonnelID = P.PersonnelID 
     GROUP BY P.OrganizationID 
) EVT 
     ON EVT.OrganizationID = T.OrganizationID 
GROUP BY T.RootOrganizationID, L.OrganizationLevel, P.OrganizationName 
+0

Я не уверен, хотите ли вы, чтобы TotalNumberParticipatingInEvent был «Число отдельных лиц, участвующих в одном или нескольких событиях» или «сумма лиц, участвующих в каждом событии». Вышеприведенный запрос делает последнее, но легко будет меняться в первом - просто измените подзапрос ... –

+0

Я не уверен, что техника получает определенное имя - по крайней мере, не то, что я знаю ...! –