将光标转换为基于集合的操作

时间:2013-03-14 18:51:06

标签: sql sql-server sql-server-2008 tsql

所以我有这个查询按ID搜索id并相应地计算成本。但是非常慢,我想了解如何将其转换为基于集合的操作。

因此,根据我们的情况,我们会以不同的方式计算模型成本。

当用户更新驱动程序时,我们可以根据更改的位置对整个驱动程序列运行更新。

但是在计算建模成本方面。 我们逐行执行,因为固定成本不同然后除以月。我已粘贴下面的代码。基于集合的操作还有办法解决这个问题吗?

首先,我们根据使用更新更改的值更新同一个表中的驱动程序,然后逐行更新建模的成本(这非常慢)

代码:

SELECT @rowCounter = 1, @totalrows = @@ROWCOUNT

WHILE @rowCounter <= @totalrows
    BEGIN

        SELECT @currentId = tempId
        FROM @temp
        WHERE row = @rowCounter     

        SELECT  
                @newModeledCost = 
                case when not exists (select 1 from dbo.DIMSTD_SCENARIO where SCENARIO0_Name = SCENARIO and SCENARIO2_Name = 'Model') then 
                ISNULL(DriverValue1,0)*ISNULL(DriverValue2,0)*ISNULL(UnitA,0)*ISNULL(UnitB,0)+ISNULL(FixedCost,0) 
                -- normal allocation for all scenarios
                else
                (ISNULL(unita,0) * (ISNULL(DriverValue1,0)/ISNULL(NULLIF(DriverValue2,0),1))* ISNULL(UnitB,0))+ISNULL(FixedCost,0)  
                --(ISNULL(unita,0) * (ISNULL(DriverValue1,0)/ISNULL(DriverValue2,0))*ISNULL(UnitB,0))+ISNULL(FixedCost,0) 
                -- allocation for model scenarios
                end
                ,                                       
                @oldModeledCost = ISNULL(ModeledCost,0),
                @newOct = (ISNULL(@newModeledCost,0) * (ISNULL(Oct, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newNov = (ISNULL(@newModeledCost,0) * (ISNULL(Nov, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newDec = (ISNULL(@newModeledCost,0) * (ISNULL(Dec, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newJan = (ISNULL(@newModeledCost,0) * (ISNULL(Jan, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newFeb = (ISNULL(@newModeledCost,0) * (ISNULL(Feb, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newMar = (ISNULL(@newModeledCost,0) * (ISNULL(Mar, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newApr = (ISNULL(@newModeledCost,0) * (ISNULL(Apr, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newMay = (ISNULL(@newModeledCost,0) * (ISNULL(May, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newJun = (ISNULL(@newModeledCost,0) * (ISNULL(Jun, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newJul = (ISNULL(@newModeledCost,0) * (ISNULL(Jul, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newAug = (ISNULL(@newModeledCost,0) * (ISNULL(Aug, 0) /ISNULL(NULLIF(@oldModeledCost,0),1))),
                @newSep = (ISNULL(@newModeledCost,0) * (ISNULL(Sep, 0) /ISNULL(NULLIF(@oldModeledCost,0),1)))
        FROM dbo.TBF_BUDGETExpenses
        WHERE BudgetId = @currentId 
        --and not exists (select 1 from dbo.DIMSTD_SCENARIO where SCENARIO0_Name = SCENARIO and SCENARIO2_Name = 'Model')

        UPDATE dbo.TBF_BUDGETExpenses
        SET ModeledCost = @newModeledCost,
            Oct = @newOct,
            Nov = @newNov,
            Dec = @newDec,
            Jan = @newJan,
            Feb = @newFeb,
            Mar = @newMar,
            Apr = @newApr,
            May = @newMay,
            Jun = @newJun,
            Jul = @newJul,
            Aug = @newAug,
            Sep = @newSep,
            Username = 'Cascade',
            lastmodified = getdate()                
        WHERE BudgetId = @currentId
        AND @oldModeledCost <> 0

        Print 'Record Update ' + CAST(@currentId AS VARCHAR(15))

        SET @rowCounter = @rowCounter + 1

END

2 个答案:

答案 0 :(得分:0)

如果没有完整的架构,测试数据和预期结果,很难验证这一点。这是基于快速设置的当前更新的重现。注意:我将ModeledCost CASE向下移动到子查询中,以避免在每个列集中重复它。由你决定是否具有逻辑意义......我认为BudgetId是PK。

将更新作为SELECT运行以确认其生成所需的结果集:

select  t.BudgetId,
        --
        Oct = (ISNULL(new.ModeledCost,0) * (ISNULL(Oct, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Nov = (ISNULL(new.ModeledCost,0) * (ISNULL(Nov, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Dec = (ISNULL(new.ModeledCost,0) * (ISNULL(Dec, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Jan = (ISNULL(new.ModeledCost,0) * (ISNULL(Jan, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Feb = (ISNULL(new.ModeledCost,0) * (ISNULL(Feb, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Mar = (ISNULL(new.ModeledCost,0) * (ISNULL(Mar, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Apr = (ISNULL(new.ModeledCost,0) * (ISNULL(Apr, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        May = (ISNULL(new.ModeledCost,0) * (ISNULL(May, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Jun = (ISNULL(new.ModeledCost,0) * (ISNULL(Jun, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Jul = (ISNULL(new.ModeledCost,0) * (ISNULL(Jul, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Aug = (ISNULL(new.ModeledCost,0) * (ISNULL(Aug, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Sep = (ISNULL(new.ModeledCost,0) * (ISNULL(Sep, 0) /ISNULL(NULLIF(t.ModeledCost,0),1)))
        Username = 'Cascade',
        lastmodified = getdate(),
        ModeledCost = new.ModeledCost
from    dbo.TBF_BUDGETExpenses as [t]
left
join    (   select  BudgetId,
                    case
                        when not exists (select 1 from dbo.DIMSTD_SCENARIO where SCENARIO0_Name = SCENARIO and SCENARIO2_Name = 'Model') 
                        then ISNULL(DriverValue1,0)*ISNULL(DriverValue2,0)*ISNULL(UnitA,0)*ISNULL(UnitB,0)+ISNULL(FixedCost,0) 
                        -- normal allocation for all scenarios
                        else (ISNULL(unita,0) * (ISNULL(DriverValue1,0)/ISNULL(NULLIF(DriverValue2,0),1))* ISNULL(UnitB,0))+ISNULL(FixedCost,0)  
                            --(ISNULL(unita,0) * (ISNULL(DriverValue1,0)/ISNULL(DriverValue2,0))*ISNULL(UnitB,0))+ISNULL(FixedCost,0) 
                            -- allocation for model scenarios
                    end
            from    dbo.TBF_BUDGETExpenses
        ) as new(BudgetId, ModeledCost) on t.BudgetId = new.BudgetId
where   ISNULL(t.ModeledCost,0) <> 0

作为UPDATE

update  t
set     Oct = (ISNULL(new.ModeledCost,0) * (ISNULL(Oct, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Nov = (ISNULL(new.ModeledCost,0) * (ISNULL(Nov, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Dec = (ISNULL(new.ModeledCost,0) * (ISNULL(Dec, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Jan = (ISNULL(new.ModeledCost,0) * (ISNULL(Jan, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Feb = (ISNULL(new.ModeledCost,0) * (ISNULL(Feb, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Mar = (ISNULL(new.ModeledCost,0) * (ISNULL(Mar, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Apr = (ISNULL(new.ModeledCost,0) * (ISNULL(Apr, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        May = (ISNULL(new.ModeledCost,0) * (ISNULL(May, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Jun = (ISNULL(new.ModeledCost,0) * (ISNULL(Jun, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Jul = (ISNULL(new.ModeledCost,0) * (ISNULL(Jul, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Aug = (ISNULL(new.ModeledCost,0) * (ISNULL(Aug, 0) /ISNULL(NULLIF(t.ModeledCost,0),1))),
        Sep = (ISNULL(new.ModeledCost,0) * (ISNULL(Sep, 0) /ISNULL(NULLIF(t.ModeledCost,0),1)))
        Username = 'Cascade',
        lastmodified = getdate(),
        ModeledCost = new.ModeledCost
from    dbo.TBF_BUDGETExpenses as [t]
left
join    (   select  BudgetId,
                    case
                        when not exists (select 1 from dbo.DIMSTD_SCENARIO where SCENARIO0_Name = SCENARIO and SCENARIO2_Name = 'Model') 
                        then ISNULL(DriverValue1,0)*ISNULL(DriverValue2,0)*ISNULL(UnitA,0)*ISNULL(UnitB,0)+ISNULL(FixedCost,0) 
                        -- normal allocation for all scenarios
                        else (ISNULL(unita,0) * (ISNULL(DriverValue1,0)/ISNULL(NULLIF(DriverValue2,0),1))* ISNULL(UnitB,0))+ISNULL(FixedCost,0)  
                            --(ISNULL(unita,0) * (ISNULL(DriverValue1,0)/ISNULL(DriverValue2,0))*ISNULL(UnitB,0))+ISNULL(FixedCost,0) 
                            -- allocation for model scenarios
                    end
            from    dbo.TBF_BUDGETExpenses
        ) as new(BudgetId, ModeledCost) on t.BudgetId = new.BudgetId
where   ISNULL(t.ModeledCost,0) <> 0

答案 1 :(得分:0)

对于你的情况,肯定设置操作更好,更可行,但我认为最好的方法是不使用任何查询,而是使用表的DDL。创建表时,可以使用持久性创建计算列。就像您的十二个月的列一样,它们可以是计算列,并且所有因素都可以从同一个表中计算出来。这是链接:http://msdn.microsoft.com/en-us/library/ms186241.aspx