如何在 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
我有一个 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