Как я могу упростить SQL-запрос? - PullRequest
0 голосов
/ 25 сентября 2019

У меня есть запрос ниже, который не работает на сервере SQL с большим количеством данных.Запрос не работает, когда я использую фильтр даты с 3 комбинациями в предложении where.

      IF OBJECT_ID('tempdb..#tempAllocStatus1') IS NOT NULL
                     DROP TABLE #tempAllocStatus1 

                     SELECT  Users.Name,REPLACE(Staff.Designation, 'IND ', '') as Designation, Staff.Office as Location,
                                    (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt  
                                    INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                                    WHERE ReqDt.AssignedToID = Users.UserADID AND Req.TypeOfRequest = 1 AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENRE' or ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRR' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF'))) [Indian Benchmarking Assigned], 

                                    (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt  
                                    INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                                    WHERE ReqDt.ReviewerID = Users.UserADID AND Req.TypeOfRequest = 1 AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF' or SubStatusCode='RPC' or SubStatusCode='TPRPC'))) [Indian Benchmarking Reviewer], 

                                    (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt  
                                    INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                                    WHERE ReqDt.SignoffID = Users.UserADID AND Req.TypeOfRequest = 1 AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='RPSOFF' or ReqDt.SubStatusCode='SCPC' or ReqDt.SubStatusCode='TPSCPC'))) [Indian Benchmarking Signoff],

                                    (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt  
                                    INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                                    WHERE ReqDt.AssignedToID = Users.UserADID AND Req.TypeOfRequest = 1 AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENRE' or ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRR' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF'))) + 
                                    (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt  
                                    INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                                    WHERE ReqDt.ReviewerID = Users.UserADID AND Req.TypeOfRequest = 1 AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF' or SubStatusCode='RPC' or SubStatusCode='TPRPC'))) + 
                                    (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt  
                                    INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                                    WHERE ReqDt.SignoffID = Users.UserADID AND Req.TypeOfRequest = 1 AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='RPSOFF' or ReqDt.SubStatusCode='SCPC' or ReqDt.SubStatusCode='TPSCPC'))) [Indian Benchmarking Total],


                       (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt 
                        WHERE ReqDt.AssignedToID = Users.UserADID AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENRE' or ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRR' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF'))) [All Assigned], 
                        (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt 
                        WHERE ReqDt.ReviewerID = Users.UserADID AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF' or SubStatusCode='RPC' or SubStatusCode='TPRPC'))) [All Reviewer], 
                        (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt 
                        INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                        WHERE ReqDt.SignoffID = Users.UserADID AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='RPSOFF' or ReqDt.SubStatusCode='SCPC' or ReqDt.SubStatusCode='TPSCPC'))) [All Signoff],
                        (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt 
                        WHERE ReqDt.AssignedToID = Users.UserADID AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENRE' or ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRR' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF'))) + 
                        (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt 
                        WHERE ReqDt.ReviewerID = Users.UserADID AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='BENSF' or ReqDt.SubStatusCode='DRSO' or ReqDt.SubStatusCode='RPSOFF' or SubStatusCode='RPC' or SubStatusCode='TPRPC'))) + 
                        (SELECT  COUNT(ReqDt.ID) FROM tblTPRequestDetail ReqDt 
                        INNER JOIN  tblTPRequest Req ON ReqDt.RequestID = Req.Id 
                        WHERE ReqDt.SignoffID = Users.UserADID AND ((ReqDt.StatusCode = 'COMP' or ReqDt.StatusCode = 'PCR') or (ReqDt.StatusCode = 'AWIP' and ReqDt.SubStatusCode='RPSOFF' or ReqDt.SubStatusCode='SCPC' or ReqDt.SubStatusCode='TPSCPC'))) [All Total]

                        INTO #tempAllocStatus1

                        FROM tblUserRolesMapping Users

                            LEFT JOIN [tblstaff] Staff ON Users.UserADID = Staff.AD_Id                                  
                            LEFT JOIN tblTPRequestDetail UserAssigned ON UserAssigned.AssignedToID = Users.UserADID
                            LEFT JOIN tblTPRequestDetail UserReviewer ON UserReviewer.ReviewerID = Users.UserADID
                            LEFT JOIN tblTPRequestDetail UserSignoff ON UserSignoff.SignoffID = Users.UserADID

                            LEFT JOIN tblTPRequest TPRAssigned ON UserAssigned.RequestID = TPRAssigned.ID
                            LEFT JOIN tblTPRequest TPRReviewer ON UserReviewer.RequestID = TPRReviewer.ID
                            LEFT JOIN tblTPRequest TPRSignoff ON UserSignoff.RequestID = TPRSignoff.ID 

                        WHERE Users.Active = 1 and Users.[RoleId] !=6
                                  AND (TPRAssigned.crtddate >= '2017-04-01'  and TPRAssigned.crtddate<= '2017-05-30')

                                  OR (TPRReviewer.crtddate >= '2017-04-01'  AND TPRReviewer.crtddate<='2017-05-30')

                                  OR (TPRSignoff.crtddate >= '2017-04-01'  AND TPRSignoff.crtddate<='2017-05-30' )
                                   GROUP BY Users.UserADID,  Users.Name, Staff.Designation,Staff.Office 

                            SELECT * FROM #tempAllocStatus1 WHERE [All Total] > 0

                                UNION ALL

                            SELECT * FROM #tempAllocStatus1 WHERE [All Total] = 0 

И я столкнулся с проблемой в следующих строках запроса.

                             AND (TPRAssigned.crtddate >= '2017-04-01'  and TPRAssigned.crtddate<= '2017-05-30')

                                  OR (TPRReviewer.crtddate >= '2017-04-01'  AND TPRReviewer.crtddate<='2017-05-30')


                                  OR (TPRSignoff.crtddate >= '2017-04-01'  AND TPRSignoff.crtddate<='2017-05-30')

Iперепробовал много решений, чтобы упростить этот запрос.Но ничего не работает с большим количеством данных.Это обработка в течение длительного времени и получение тайм-аута.Может кто-нибудь, пожалуйста, помогите упростить этот запрос?

Согласно предложению, я оптимизировал запрос, как показано ниже.

   select
    ReqDt.AssignedToID,
    COUNT(*) NumRecs 
into
    #tmpAssigned
from
    tblTPRequestDetail ReqDt
        INNER JOIN  tblTPRequest Req 
            ON ReqDt.RequestID = Req.Id
            AND Req.TypeOfRequest = 1 

            AND Req.crtddate >= '2017-04-01'  
            and Req.crtddate <= '2022-05-30'
WHERE

        ReqDt.StatusCode IN ( 'COMP', 'PCR' ) 
    OR (    ReqDt.StatusCode = 'AWIP' 
        and ReqDt.SubStatusCode IN ( 'BENRE', 'BENSF', 'DRR', 'DRSO', 'RPSOFF' )
       )
GROUP BY
    ReqDt.AssignedToID



    select
    ReqDt.ReviewerID,
    COUNT(*) NumRecs
into
    #tmpReviewed
from
    tblTPRequestDetail ReqDt
        INNER JOIN  tblTPRequest Req 
            ON ReqDt.RequestID = Req.Id
           AND Req.TypeOfRequest = 1 

           AND Req.crtddate >= '2017-04-01'  
           and Req.crtddate <= '2022-05-30'
WHERE

        ReqDt.StatusCode IN ( 'COMP', 'PCR' ) 
    OR (    ReqDt.StatusCode = 'AWIP' 
        and ReqDt.SubStatusCode IN ( 'BENSF', 'DRSO', 'RPSOFF', 'RPC', 'TPRPC' )
       )
GROUP BY
    ReqDt.ReviewerID 

    select
    ReqDt.SignoffID,
    COUNT(*) NumRecs 
into
    #tmpSigned
from
    tblTPRequestDetail ReqDt
        INNER JOIN  tblTPRequest Req 
            ON ReqDt.RequestID = Req.Id
            AND Req.TypeOfRequest = 1 

            AND Req.crtddate >= '2017-04-01'  
            and Req.crtddate <= '2022-05-30'
WHERE

        ReqDt.StatusCode IN ( 'COMP', 'PCR' ) 
    OR (    ReqDt.StatusCode = 'AWIP' 
        and ReqDt.SubStatusCode IN ( 'RPSOFF', 'SCPC', 'TPSCPC' )
        )
GROUP BY
    ReqDt.SignoffID


    SELECT U.Name,
    REPLACE(S.Designation, 'IND ', '') as Designation, 
    S.Office as Location,
    coalesce( Assigned.NumRecs, 0 ) [Indian Benchmarking Assigned],
    coalesce( Reviewed.NumRecs, 0 ) [Indian Benchmarking Reviewed],
    coalesce( Signed.NumRecs, 0 ) [Indian Benchmarking Signed],
    coalesce( Assigned.NumRecs, 0 ) + coalesce( Reviewed.NumRecs, 0 ) + coalesce( Signed.NumRecs, 0 )  [total Indian Benchmarking]

from
    tblUserRolesMapping U
        left JOIN [tblstaff] S 
            ON U.UserADID = S.AD_Id

        left JOIN #tmpAssigned Assigned
            on U.UserADID = Assigned.AssignedToID

        left JOIN #tmpReviewed Reviewed
            on U.UserADID = Reviewed.ReviewerID           

        left JOIN #tmpSigned Signed
            on U.UserADID = Signed.SignoffID

WHERE 
        U.Active = 1 
    and U.RoleId !=6 
    and coalesce( Assigned.NumRecs, 0 ) + coalesce( Reviewed.NumRecs, 0 ) + coalesce( Signed.NumRecs, 0 ) !=0

order by U.Name

Но я получаю дубликаты записей.Как мне удалить дубликаты записей из результата.Также один и тот же пользователь с USERADID может иметь более одной роли в таблице tblUserRoleMapping.

1 Ответ

0 голосов
/ 25 сентября 2019

Очевидно, что это избыточно, но также учитывает ваши условия, особенно в ваших подсчетах.Глядя на ваш (StatusCode и SubStatusCode или SubStatusCode или SubStatusCode или ...).Если любое из ваших последующих условий ИЛИ будет выполнено, оно будет считаться истинным.Глядя на StatusCode = 'AWIP' и SubStatus = 'DRSO', это будет интерпретировано как

( true and false or false or true or false ) resulting in TRUE

или как-либо иначе. Глядя на StatusCode = 'XYZ' и SubStatus = 'DRSO', это будет интерпретироваться как

( false and false or false or true or false ) resulting in TRUE.

Я думаю, что вы пытаетесь выполнить (соответственно для образцов выше

( true and (false or false or true or false )) resulting in TRUE
( false and (false or false or true or false )) resulting in FALSE.

, где вы хотите, чтобы основной код состояния = 'AWIP', и если это так, то только счетесли какой-либо из кодов SUBSTATUS является одним из следующих: Ваши круглые скобки не были правильно размещены, если это было задумано. Переход на предложение IN () может помочь упростить эту неоднозначность.

Теперь с дублированием, еслиэто предварительно написано как подзапрос, сгруппированный по идентификатору пользователя и получающий количество, которое вы можете присоединить к нему один раз

Поскольку вы уже используете временные таблицы "#" в SQL-сервере, вы можете запросить ихрезультаты, а затем снова sum () без идентификатора пользователя для общего итога по категории.

За комментарий дубликата STAFF необходимо получить идентификатор UNIQUE STAFF (не предоставлен, поэтому я буду указыватьИмя столбца вверх.Вы, очевидно, можете настроить это).Кроме того, из-за транзитивной ассоциации (если a = b и b = c, то a = c) я присоединюсь к таблице STAFF и получу уникальный идентификатор STAFF.Также, удалив контекст «Роль», я также составил столбец для StaffUserName.Это исключит дубликаты записей, поскольку сводит итоги по каждому ЛИЦУ, а не по РОЛЕ лиц.

select
        S.UniqueStaffID,
        COUNT(*) NumRecs 
    into
        #tmpAssigned
    from
        tblTPRequestDetail ReqDt
            JOIN [tblstaff] S 
                ON ReqDt.AssignedToID = S.AD_Id
            INNER JOIN  tblTPRequest Req 
                ON ReqDt.RequestID = Req.Id
                AND Req.TypeOfRequest = 1 
                -- apply the date filters directly to where you are getting queries 
                AND Req.crtddate >= '2017-04-01'  
                and Req.crtddate <= '2017-05-30'
    WHERE
            -- and only getting same criteria
            ReqDt.StatusCode IN ( 'COMP', 'PCR' ) 
        OR (    ReqDt.StatusCode = 'AWIP' 
            and ReqDt.SubStatusCode IN ( 'BENRE', 'BENSF', 'DRR', 'DRSO', 'RPSOFF' )
           )
    GROUP BY
        S.UniqueStaffID


select
        S.UniqueStaffID,
        COUNT(*) NumRecs
    into
        #tmpReviewed
    from
        tblTPRequestDetail ReqDt
            JOIN [tblstaff] S 
                ON ReqDt.AssignedToID = S.AD_Id
            INNER JOIN  tblTPRequest Req 
                ON ReqDt.RequestID = Req.Id
               AND Req.TypeOfRequest = 1 
               -- apply the date filters directly to where you are getting queries 
               AND Req.crtddate >= '2017-04-01'  
               and Req.crtddate <= '2017-05-30'
    WHERE
        -- and only getting same criteria
            ReqDt.StatusCode IN ( 'COMP', 'PCR' ) 
        OR (    ReqDt.StatusCode = 'AWIP' 
            and ReqDt.SubStatusCode IN ( 'BENSF', 'DRSO', 'RPSOFF', 'RPC', 'TPRPC' )
           )
    GROUP BY
        S.UniqueStaffID 


select
        S.UniqueStaffID,
        COUNT(*) NumRecs 
    into
        #tmpSigned
    from
        tblTPRequestDetail ReqDt
            JOIN [tblstaff] S 
                ON ReqDt.AssignedToID = S.AD_Id
            INNER JOIN  tblTPRequest Req 
                ON ReqDt.RequestID = Req.Id
                AND Req.TypeOfRequest = 1 
                -- apply the date filters directly to where you are getting queries 
                AND Req.crtddate >= '2017-04-01'  
                and Req.crtddate <= '2017-05-30'
    WHERE
            -- and only getting same criteria
            ReqDt.StatusCode IN ( 'COMP', 'PCR' ) 
        OR (    ReqDt.StatusCode = 'AWIP' 
            and ReqDt.SubStatusCode IN ( 'RPSOFF', 'SCPC', 'TPSCPC' )
            )
    GROUP BY
        S.UniqueStaffID



SELECT
        S.StaffUserName,
        REPLACE(S.Designation, 'IND ', '') as Designation, 
        S.Office as Location,
        coalesce( Assigned.NumRecs, 0 ) [Indian Benchmarking Assigned],
        coalesce( Reviewed.NumRecs, 0 ) [Indian Benchmarking Reviewed],
        coalesce( Signed.NumRecs, 0 ) [Indian Benchmarking Signed],
        coalesce( AllAssigned.NumRecs, 0 ) [All Indian Benchmarking Assigned],
        coalesce( AllReviewed.NumRecs, 0 ) [All Indian Benchmarking Reviewed],
        coalesce( AllSigned.NumRecs, 0 ) [All Indian Benchmarking Signed],
        coalesce( AllAssigned.NumRecs, 0 ) 
            + coalesce( AllReviewed.NumRecs, 0 ) 
            + coalesce( AllSigned.NumRecs, 0 ) [AllRecords]
    from
        JOIN [tblstaff] S 
            LEFT JOIN #tmpAssigned Assigned
                on S.UniqueStaffID = Assigned.UniqueStaffID
            JOIN
            ( select sum(NumRecs) NumRecs 
                from #tmpAssigned ) AllAssigned
                on 1=1

            LEFT JOIN #tmpReviewed Reviewed
                on S.UniqueStaffID = Reviewed.UniqueStaffID
            JOIN
            ( select sum(NumRecs) NumRecs 
                from #tmpReviewed ) AllReviewed
                on 1=1

            LEFT JOIN #tmpSigned Signed
                on S.UniqueStaffID = Signed.UniqueStaffID
            JOIN
            ( select sum(NumRecs) NumRecs 
                from #tmpSigned ) AllSigned
                on 1=1
    WHERE 
            U.Active = 1 
        and U.RoleId !=6
    ORDER BY 
        S.StaffUserName, 
        S.Designation,
        S.Office 

Поскольку предварительный запрос Назначенных, Проверенных и Подписанных предварительно агрегирован не более,одна запись пользователя за раз, вам не нужно использовать группу на внешнем уровне.Кроме того, для «ВСЕГО» назначенных, проверенных, подписанных, поскольку они не сгруппированы, они всегда будут одной записью, представляющей весь квалифицированный пул записей соответствующих категорий.Должно помочь вам выполнить ваш запрос и его итоги, как вы пытались.

Обновление обратной связи для комментария.

Я не использую "разные" в моем запросе, и вы, должно быть, добавили это.Что касается того, почему, я могу только предположить, что один идентификатор пользователя ROLE может быть связан с несколькими сотрудниками?Если вы можете отредактировать свой исходный пост и поделиться некоторыми ОБРАЗЦАМИ Данных, представляющих такие РОЛИ и ПЕРСОНАЛ, это может помочь (и сделать пару ролей / сотрудников, чтобы увидеть лучшую корреляцию и, очевидно, ничего действительно конфиденциального / конфиденциального).Вероятно, это источник нескольких записей.

У меня сложилось впечатление, что «UserADID» был уникальным пользователем, а не РОЛЕ пользователя, так как этот идентификатор был назначен для детали запроса.Я могу только догадываться о влиянии, но теперь думаю, что у вас может быть что-то вроде

ApprovingRole ID = 1
   Office 1 Staff person ID X
   Office 2 Staff Person ID Y
   Office 3 Staff Person ID Z

ReviewingRole ID = 2
   Office 2 Staff person ID A
   Office 2 Staff Person ID Y
   Office 4 Staff person ID B

SigningRole ID = 3
   Office 2 Staff Person ID Y
   Office 4 Staff person ID B

В приведенных выше «примерных данных» вы можете видеть, что сотрудник «Y» является членом всех трех ролей.Штатный сотрудник "B" является членом двух ролей.

etc

Итак, какой "ID" действительно обрабатывается здесь.Является ли Утверждающий «Роль» ID 1 привязанным к деталям запроса, или это СОТРУДНИК, к которому привязаны X, Y, Z.

Если данные такие, как у меня, и из-за отсутствия образцов данных,Как бы я узнал, с каким сайтом / назначением персонала связаны основные показатели.Итоговые значения в противном случае представляют идентификатор пользователя ROLD, а не идентификатор пользователя STAFF.Дайте мне знать иначе, и я могу редактировать результаты.

Итак, теперь вы заявляете, что есть дубликаты для того же пользователя!не пользователь РОЛЬ!В этом случае нам нужно, чтобы каждая временная температура предварительного запроса была полностью связана с идентификатором USER STAFF, а не с идентификатором ROLE.Я изменил запросы выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...