如何在T-SQL视图中重用子查询

时间:2019-06-12 23:58:26

标签: sql sql-server tsql common-table-expression sql-view

我有一个要优化的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,但是问题是我需要了解Advanced的ProjectId,所以这行不通。我不想使用联接,因为我希望此视图中的每个记录成为该项目的唯一记录。这里有什么建议吗?我可以通过某种方式将这些Tasks分组或重新使用结果集?

2 个答案:

答案 0 :(得分:2)

您可以使用相关的子查询来计算所有总数:

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 :(得分:1)

由于只有一组分组,因此查询可以简化为:

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