在SQL中进行计算的正确方法

时间:2011-06-20 15:40:50

标签: sql db2

Baseline Table

ProjectId   ProjectName    Forecast
---------   -----------    --------
  11258      Test Proj1      0.678 
  11259      Test Proj2      2.57 

FundEntity Baseline Table

ProjectId    FundEntityId    Forecast    ForecastDollars
---------    -----------     --------    ---------------
  11258          5             0.226
  11258          8             0.226
  11258          11            0.226 

我有一个存储过程循环遍历ProjectSummaryEntity表(Yuck!)中的每个条目,并且对于每个条目,根据FundEntity表中设置的“分配”中断预测。然后,我需要根据“费率”表中的特定费率计算预测的美元金额。费率也由FundEntity决定。

存储过程运行有点慢(6.6k行为14s),由于代码效率低下,我并不感到惊讶。我的问题是,如何在不使用游标的情况下“即时”进行计算?

我使用游标的原因是:

  • 预测金额首先被细分(来自ProjectSummary),保存到变量
  • 确定费率,保存为变量
  • 确定美元金额,保存到变量
  • 运行最终更新语句以更新预测和预测美元

如果我不使用游标,则无法根据预测更新美元。任何帮助表示赞赏。谢谢!

编辑:以上是整个事情的真正简化版本。处理此问题的存储过程位于:http://pastebin.ubuntu.com/629888/

1 个答案:

答案 0 :(得分:1)

请注意,存储过程的运行速度不是因为您的光标,而是因为您需要每行运行子查询(11选择+ 1更新)。只需组合其中一些查询,您就可以显着提高性能(例如forHcm,budgetHcm和revPlanHcm的计算可以很容易地连接到一个查询中,因为它们都是基线表列的计算)。

要回答您的特定光标问题,可以删除光标,因为您不需要根据其他行的输出值生成行输出值(例如,如果使用hcmRate值计算一个fundEntityBaselineId的hcmRate值对于另一个FundEntityBaselineId值,则很难避免游标)。 没有光标的最终查询会有点复杂。

将您的存储过程放在http://pastebin.ubuntu.com/629888/并假设如果您使用COALESCE我需要一个OUTER JOIN(没有COALESCE然后INNER JOIN),这是您的单个查询应该是什么样的(修复标记为“refactor”的部分) “我需要更多地了解你的表格:”

SELECT fblId,
       ForecastAmount * fundAlloc AS foreHCM
       hcmRate,
       RE_Value * fundAlloc AS reqForeHcm,
       PlanAmount * fundAlloc AS budgetHcm
       RevisedPlanAmount * fundAlloc AS revPlanHcm,
       actualForHcm_pre * fundAlloc AS actualForeCastHcm
FROM
(SELECT b.FundEntityBaselineId AS fblId,
        COALESCE(fa.fundAllocation,100)/100 as fundAlloc,
        COALESCE(hcmRate1.Usd_Rate,hcmRate2.HCMRate) as hcmRate,
        bl.ForecastAmount,
        COALESCE(re.Value,0) as RE_Value,
        planHcmRate.BudgetHcmRate as planHcmRate,
        bl.PlanAmount,
        bl.RevisedPlanAmount,
        COALESCE(afp_p.actualForHcm_pre,0) as actualForHcm_pre
        FROM FundEntityBaseline b
          INNER JOIN ProjectDetail pd ON pd.ProjectId = b.fblProjectId
          INNER JOIN Baseline bl on bl.BaselineId = b.BaselineId
          INNER JOIN ProjectTeam pt ON bl.ProjectTeamId = pt.ProjectTeamId
        INNER JOIN SiteTeam st ON pt.SiteTeamId = st.SiteTeamId
        INNER JOIN TeamRole tr ON st.TeamRoleId = tr.RoleId
        INNER JOIN Team t ON tr.TeamId = t.TeamId
          INNER JOIN FundSource fs on fs.FundSourceId = pd.FundSourceId
          INNER JOIN (<* refactor*> SELECT r.BudgetHcmRate
                           FROM Rate r WHERE r.RateName = (SELECT st.RateName
                                                           FROM SiteTeam st INNER JOIN ProjectTeam pt 
                                                                                ON st.SiteTeamId = pt.SiteTeamId
                                                                            INNER JOIN Baseline bl 
                                                                                ON bl.ProjectTeamId = pt.ProjectTeamId
                                                           WHERE bl.BaselineId = fblBaselineId
                                                           FETCH FIRST 1 ROW ONLY)
                           ORDER BY r.EffectiveDate
                           FETCH FIRST 1 ROW ONLY) as planHcmRate,
          LEFT OUTER JOIN (SELECT er.Usd_Rate
                            FROM FundEntity fe
                                INNER JOIN EntityCustomerRate er
                                    ON fe.FundAux1 = er.EntityCustomerRateId) AS hcmRate1 
                                    ON hcmRate1.FundEntityId = b.FundEntityId AND (fs.FundingType IN ('Direct Bill-Single','Direct Bill-Multiple')) AND t.teamType = 'ITDEVMO'
          LEFT OUTER JOIN (<* refactor*> SELECT r.HCMRate
                             FROM Rate r
                                INNER JOIN SiteTeam st ON r.RateName = st.RateName
                                INNER JOIN ProjectTeam pt ON st.SiteTeamId = pt.SiteTeamId
                             WHERE pt.ProjectTeamId = (SELECT bl.ProjectTeamId
                                                       FROM Baseline bl
                                                       WHERE bl.BaselineId = b.BaselineId)
                             ORDER BY r.EffectiveDate DESC
                             FETCH FIRST 1 ROW ONLY) as hcmRate2 ON (fs.FundingType NOT IN ('Direct Bill-Single','Direct Bill-Multiple') OR t.teamType != 'ITDEVMO')
          LEFT OUTER JOIN FundAllocation fa on fa.FundSourceId = pd.FundSourceId AND fa.FundEntityId = b.fblFundEntity
          LEFT OUTER JOIN Request re on bl.ProjectMonth = re.ProjectMonth AND bl.ProjectTeamId = re.ProjectTeamId AND re.BaselineType = 'Reforecast'
          LEFT OUTER JOIN (<*refactor *>SELECT (((SELECT SUM(bl.ForecastAmount) 
                              FROM Baseline bl 
                              WHERE DATE(SUBSTR(bl.ProjectMonth, 5) || '-' || 
                                        (CASE SUBSTR(bl.ProjectMonth, 1, 3)
                                             WHEN 'Jan' THEN '01'
                                             WHEN 'Feb' THEN '02'
                                             WHEN 'Mar' THEN '03'
                                             WHEN 'Apr' THEN '04'
                                             WHEN 'May' THEN '05'
                                             WHEN 'Jun' THEN '06'
                                             WHEN 'Jul' THEN '07'
                                             WHEN 'Aug' THEN '08'
                                             WHEN 'Sep' THEN '09'
                                             WHEN 'Oct' THEN '10'
                                             WHEN 'Nov' THEN '11'
                                             WHEN 'Dec' THEN '12'
                                         END) || '-01') > DATE((SELECT CurrentMonth FROM Pmo)) AND
                                    bl.ProjectTeamId = (SELECT ProjectTeamId FROM Baseline WHERE BaselineId = fblBaselineId)) 
                              +
                             (SELECT SUM(bl.HcmActualAmount) 
                              FROM Baseline bl 
                              WHERE DATE(SUBSTR(bl.ProjectMonth, 5) || '-' || 
                                        (CASE SUBSTR(bl.ProjectMonth, 1, 3)
                                             WHEN 'Jan' THEN '01'
                                             WHEN 'Feb' THEN '02'
                                             WHEN 'Mar' THEN '03'
                                             WHEN 'Apr' THEN '04'
                                             WHEN 'May' THEN '05'
                                             WHEN 'Jun' THEN '06'
                                             WHEN 'Jul' THEN '07'
                                             WHEN 'Aug' THEN '08'
                                             WHEN 'Sep' THEN '09'
                                             WHEN 'Oct' THEN '10'
                                             WHEN 'Nov' THEN '11'
                                             WHEN 'Dec' THEN '12'
                                         END) || '-01') <= DATE((SELECT CurrentMonth FROM Pmo)) AND
                                    bl.ProjectTeamId = (SELECT ProjectTeamId FROM Baseline WHERE BaselineId = fblBaselineId))) as actualForeHcm_pre) AS afh_p
        WHERE ProjectId = projId) as T;

如果这有用,或者您需要更多解释,请告诉我。