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

How to reuse subquery in T-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,但问题是我需要预先知道 ProjectId,所以这不会很有效。我不想使用联接,因为我希望此视图中的每条记录都是该项目的唯一记录。这里有什么建议吗?我可以通过某种方式对这些进行分组 Tasks 或重用结果集?

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

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 ...

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

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