Как повторно использовать подзапрос в T-SQL View - PullRequest
0 голосов
/ 13 июня 2019

У меня есть представление SQL, которое я пытаюсь оптимизировать.Здесь соотношение один-ко-многим, у одного проекта много задач:

create view [schema].[vName]
    select p.ProjectId as 'ProjectId'
            -- ...
            -- excluded some selected columns and subqueries where this comment is
            -- ...

            , (select count(t.TaskId)
               from Task t with (nolock)
               where t.PrimarySearchEntityId = p.ProjectId and t.IsDeleted = 0) as 'Total_Tasks'
            , (select count(t.TaskId)
               from Task t with (nolock)
               where t.PrimarySearchEntityId = p.ProjectId and isnull(t.taskowner, 'Unassigned') <> 'Unassigned' and t.IsDeleted = 0) as 'Assigned_Tasks'
            , (select count(t.TaskId)
               from Task t with (nolock)
               where t.PrimarySearchEntityId = p.ProjectId and t.TaskStatusId in (400, 500) and
                   t.IsDeleted = 0) as 'Completed_Tasks'
            , (select count(t.TaskId)
               from Task t with (nolock)
               where t.PrimarySearchEntityId = p.ProjectId and t.TaskStatusId not in (400, 500) and
                   t.IsDeleted = 0) as 'Remaining_Tasks'
            , (select count(t.TaskId)
               from Task t with (nolock)
               where t.PrimarySearchEntityId = p.ProjectId and t.DueDate < getutcdate() and t.TaskStatusId not in (400, 500) and t.IsDeleted = 0) as 'Late_Tasks'
            , (select (case when count(t.taskid) > 0 then 'Overdue' else 'all' end)
               from Task t with (nolock)
    from project p with (nolock)
    -- there are some additional joined tables here ...

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

select * from Task where IsDeleted = 0 and Task.PrimarySearchEntityId = p.ProjectId

Как я могу просто повторно использовать этот набор результатов, а затем отфильтровать?Я мог бы использовать cte, но проблема в том, что мне нужно знать ProjectId заранее, так что это не будет работать.Я не хочу использовать объединение, потому что хочу, чтобы каждая запись в этом представлении была единственной записью для этого проекта.Есть ли какие-либо предложения здесь?Каким-то образом я могу сгруппировать эти Tasks или повторно использовать набор результатов?

Ответы [ 2 ]

2 голосов
/ 13 июня 2019

Вы можете использовать коррелированный подзапрос, который вычислит все ваши итоги:

create view [schema].[vName]
as

select p.ProjectId as 'ProjectId',
    tsk.Total_Tasks, tsk.Assigned_Tasks, tsk.Completed_Tasks, tsk.Remaining_Tasks,
    ...
from project p with (nolock)
    cross apply (
        select count(*) as [Total_Tasks],
            count(case when t.taskowner != 'Unassigned' then 1 end) as [Assigned_Tasks],
            count(case when t.TaskStatusId in (400, 500) then 1 end) as [Completed_Tasks],
            count(case when t.TaskStatusId not in (400, 500) then 1 end) as [Remaining_Tasks],
            -- Et cetera, ad infinitum...
        from dbo.Task t
        where t.PrimarySearchEntityId = p.ProjectId and t.IsDeleted = 0
    ) tsk
-- there are some additional joined tables here ...
1 голос
/ 13 июня 2019

Поскольку у вас есть только один набор группировок, запрос можно упростить до следующего:

select p.ProjectId, 
    count(t.TaskId) as Total_Tasks,
    count(case when t.taskowner != 'Unassigned' then 1 end) as Assigned_Tasks,
    count(case when t.TaskStatusId in (400, 500) then 1 end) as Completed_Tasks,
    count(case when t.TaskStatusId not in (400, 500) then 1 end) as Remaining_Tasks,
    count(case when t.DueDate < getutcdate() and t.TaskStatusId not in (400, 500) then 1 end) as Late_Tasks
from project p with (nolock)
left join dbo.Task t on t.PrimarySearchEntityId = p.ProjectId and t.IsDeleted = 0
group by p.ProjectId

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

select p.ProjectId, Total_Tasks, Assigned_Tasks, Completed_Tasks, Remaining_Tasks, Late_Tasks
from project p
left join (
    select
        PrimarySearchEntityId,
        count(TaskId) as Total_Tasks,
        count(case when taskowner != 'Unassigned' then 1 end) as Assigned_Tasks,
        count(case when skStatusId in (400, 500) then 1 end) as Completed_Tasks,
        count(case when t.TaskStatusId not in (400, 500) then 1 end) as Remaining_Tasks,
        count(case when DueDate < getutcdate() and TaskStatusId not in (400, 500) then 1 end) as Late_Tasks
    from dbo.Task
    where IsDeleted=0
    group by PrimarySearchEntityId
) t on t.PrimarySearchEntityId = p.ProjectId 
...