下面是我指的存储过程。
/****** Object: StoredProcedure [dbo].[usp_GetReportDetails] ******/
IF OBJECT_ID(N'[usp_GetReportDetails]', N'P') IS NOT NULL
DROP PROCEDURE [dbo].[usp_GetReportDetails]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
Description : This is an SP for SSRS report dataset.
> Fetch the report details based on input filters, the input filters are multivalued-parameters (string with comma seperated values)
> Requirement is to fetch all the details for each project as a record in the output list
*/
CREATE PROCEDURE [dbo].usp_GetReportDetails
(
@sponsorg nvarchar(200),
@programname nvarchar(200),
@portfolio nvarchar(200),
@executingdep nvarchar(200),
@requestingdep nvarchar(200),
@projectmanager nvarchar(200)
)
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
declare @fy int=dbo.fnc_FiscalYear(getdate());
--PART:1
--First I am fetching the latest QPID(An ID which identifies Forecast records) for each project ID.
create table #pidQpidList(qpid int,type nvarchar(50),ProjectID int,ProjectCode nvarchar(max),ProjectName nvarchar(max))
insert into #pidQpidList
select qpid, type, ProjectID,ProjectCode,ProjectName from
( select E.qpid, e.Type,e.ProjectID,PM.ProjectCode,PM.ProjectName,ROW_NUMBER() OVER(PARTITION BY e.Type,e.projectid,e.fiscalyear ORDER BY w.date desc) as rn
FROM AmtrakQTYPLANExtension E
JOIN PROJECTProjectMain PM on PM.ProjectId=E.ProjectID AND PM.IsActive=1
left join LibraryExecutingDepartment led on led.ID=PM.ExecutingDepartment
left join LIBRARYProjectOrganization lpo on lpo.id=led.OrganizationID
AND (@Portfolio = '0' OR PM.ProjectId in (select * from fnGetProjectIdbyPortfolio(@Portfolio)))
AND (@programname = '' OR ISNULL(PM.ProjectClass,0) IN (SELECT value FROM STRING_SPLIT((@programname), ',')))
AND (@executingdep = '' OR ISNULL(lpo.id,0) IN (SELECT value FROM STRING_SPLIT((@executingdep), ',')))
AND (@requestingdep = '' OR ISNULL(PM.RequestingDepartmentID,0) IN (SELECT value FROM STRING_SPLIT((@requestingdep), ',')))
AND (@projectmanager = '' OR ISNULL(PM.ProjectManager,0) IN (SELECT value FROM STRING_SPLIT((@projectmanager), ',')))
JOIN BDGTESTBudgetEstimates be ON be.id = e.ContractID
AND be.Aur_ApprovedOn is not null
LEFT OUTER JOIN [LIBRARYBudgetEstimateType] ON [LIBRARYBudgetEstimateType].[BudgetEstimateTypeID] = be.[BudgetEstimateType]
AND LIBRARYBudgetEstimateType.BudgetEstimateTypeName='Level 1'
JOIN WorkflowFormMapping W ON W.FormInstanceID = E.QPID
AND FormID = 'XQTYPLN'
AND w.CurrentStatus NOT IN ('Draft')
) as a
where rn = 1
--these variables are to to get forecast data for specific months
declare @startmonthnumber int,@todaymonthno int;
SELECT @StartMonthNumber = Number FROM (SELECT DISTINCT CONVERT(INT, MonthNo) AS Number
,SUBSTRING(TRIM([MonthName]),len(TRIM([MonthName]))-3,4) as [Year]
,SUBSTRING(TRIM([MonthName]),0,4) as [Month]
FROM QTYPLANCalendar) AS A
WHERE Year = @fy-1 and Month= 'Oct'
select @todaymonthno = MonthNo from QTYPLANCalendar where CAST(date AS DATE)=CAST(getdate() as DATE)
--PART : 2
--For each PID-forecastID/QPID pair that I have from the above #pidQpidlist I fetch the forecast details, for specific months
--The output of this table will have 3 records for each project, one record for one type each 'Board Approved Plan','Current Plan','Forecast'
--But here is there a way I can get all data in one row ? Will attach a screenshot for better understanding
SELECT
CAST(SUM( CASE WHEN l.type='Board Approved Plan' AND sd.ScheduleID > @StartMonthNumber-1 AND sd.ScheduleID < @startmonthnumber+12 THEN sd.Quantity END) as numeric(18,2)) fyBoardPlanned,
CAST(SUM( CASE WHEN l.type='Current Plan' AND sd.ScheduleID > @StartMonthNumber-1 AND sd.ScheduleID < @startmonthnumber+12 THEN sd.Quantity END) as numeric(18,2)) fyPlanned,
CAST(SUM( CASE WHEN l.type='Forecast' AND sd.ScheduleID > @StartMonthNumber-1 AND sd.ScheduleID < @todaymonthno THEN sd.Quantity END) as numeric(18,2)) fyActuals,
CAST(SUM( CASE WHEN l.type='Forecast' AND sd.ScheduleID > @todaymonthno-1 AND sd.ScheduleID < @startmonthnumber+12 THEN sd.Quantity END) as numeric(18,2)) fyRemForecast,
l.ProjectID, l.type
into #forecastlevel1
FROM QTYPLANItemScheduleData sd
JOIN CORITEMItemDetails bd with(nolock) ON sd.ItemID=bd.ItemID
join QTYPLANMaster q with(nolock) on q.QPID=sd.QPID
inner join #pidQpidList l on q.ProjectId=l.ProjectID and sd.QPID=l.qpid
GROUP BY l.ProjectID, l.ProjectCode, l.type
--PART : 3
--fetch earliest L1 history Budget Estimate Record for each project
;with earliestL1History as (
select PID,TotalAmount from (SELECT BE.PID, BE.EstimateTotal TotalAmount,ROW_NUMBER( ) over (partition by BE.pid order by wf.date) rn
FROM BDGTESTBudgetEstimates BE
JOIN WorkflowFormMapping WF ON BE.ID = WF.FormInstanceID and FormID='BDGTEST'
where WF.CurrentStatus='Level 1 History'
) as a
where rn=1)
--PART : 4
--fetch latest L1 approved Budget Estimate Record for each project
,latestL1ApprovedRecord as (
select PID,TotalAmount from (SELECT BE.PID, BE.EstimateTotal TotalAmount,ROW_NUMBER( ) over (partition by BE.pid order by wf.date desc) rn
FROM BDGTESTBudgetEstimates BE
JOIN WorkflowFormMapping WF ON BE.ID = WF.FormInstanceID and FormID='BDGTEST'
where WF.CurrentStatus='Level 1 Approved'
) as a
where rn=1)
/*
Note : only difference between Part 3 and 4 is that the Current status, and order by wf.date. Can this be reduced to be included in one query ?
*/
--PART : 5
--fetch sum of all approved expenses for each project
,approvedExpenses as(
SELECT Ex.PID, SUM(Ex.TotCost) TotalAmount
FROM vw_AMTRAK_EXPSFRMExpenseList Ex
JOIN WorkflowFormMapping WF ON Ex.EFID = WF.FormInstanceID and FormID='EXPSFRM'
where WF.CurrentStatus='Approved'
group by Ex.PID)
--PART : 6
--Main select statement , get all the data from all the above parts joinin evertyhing based on ProjectID.
select PM.ProjectId,PM.ProjectCode,PM.ProjectName
,(CASE WHEN BEhis.TotalAmount IS NULL
THEN BEapp.TotalAmount ELSE BEhis.TotalAmount END) LOPBoardPlanned
,BEapp.TotalAmount LOPPlanned
,Ex.TotalAmount LOPActuals
,(CASE WHEN (BEapp.TotalAmount IS NULL AND Ex.TotalAmount IS NULL)
THEN NULL ELSE (ISNULL(BEapp.TotalAmount,0.00)-ISNULL(Ex.TotalAmount,0.00)) END) LOPRemainingCost
,(CASE WHEN BEapp.TotalAmount IS NULL THEN NULL
WHEN (BEhis.TotalAmount IS NULL AND ISNULL(BEapp.TotalAmount,0.00)=0) OR (BEhis.TotalAmount=0) THEN NULL
WHEN BEhis.TotalAmount IS NULL THEN 0.00
ELSE BEapp.TotalAmount-BEhis.TotalAmount END) LOPBudgetVariance
,frBA.fyBoardPlanned FYBoardPlanned
,frCP.fyPlanned FYPlanned
,frF.fyActuals FYActuals
,frF.fyRemForecast FYRemainingForecast
,(ISNULL(frCP.fyPlanned,0.00)-(ISNULL(frF.fyActuals,0.00)+ISNULL(frF.fyRemForecast,0.00))) FYBudgetVariance
from (select DISTINCT ProjectID,ProjectCode,ProjectName from #pidQpidList) PM
left join earliestL1History BEhis on BEhis.PID=PM.ProjectId
left join latestL1ApprovedRecord BEapp on BEapp.PID=PM.ProjectId
left join approvedExpenses ex on ex.PID=PM.ProjectId
left join #forecastlevel1 frBA on frBA.type='Board Approved Plan' and frBA.ProjectId=PM.ProjectId
left join #forecastlevel1 frCP on frCP.ProjectId=PM.ProjectId and frCP.type='Current Plan'
left join #forecastlevel1 frF on frF.ProjectId=PM.ProjectId and frF.type='Forecast'
drop table #pidQpidList, #forecastlevel1
END
每个项目的第 2 部分输出 请注意,在输出中,我在不同的行中获取不同类型的数据,例如; fyBoardPlanned 仅适用于 type='Board Approved Plan',因此 fyBoardPlanned 的其他两行将为空。 这部分可以优化吗?
我已经尝试优化它,但我发现报告仍然需要大量时间来加载。 PS:项目数近25k。我很紧张。
请帮助我,我缺少什么,可以减少所有查询部分?