在这种情况下如何避免光标?

时间:2014-12-23 11:46:33

标签: sql sql-server cursor

我有一个包含以下列的表

Period, WIP_Close, WIP_Open, WIP_Add, WIP_Minus.

我需要更新

  • WIP_Open = WIP_Close上一期

然后

  • 更新WIP_Close = WIP_Open + WIP_Add - WIP_Minus。

目前我使用光标如下:

declare y_curs cursor for select distinct period
        from abc
        order by period

declare @period as int
declare @old_period as int

set @old_period = 0

open y_curs
fetch y_curs into @period
while @@fetch_status = 0

begin

update f set f.wip_open = isnull(f1.wip_close,0)
from abc f join abc f1 on 1=1
where f.period = @period and f1.period=@old_period

update abc set wip_close = (isnull(wip_open,0) + wip_add - wip_minus) where period = @period

set @old_period = @period
fetch y_curs into @period

end
close y_curs
deallocate y_curs

这样可以正常工作并给出正确的结果,但是由于记录超过500万条,处理时间大约需要一个小时。

有没有更好的方法可以避免光标以获得更好的性能?

感谢您的任何建议。

此致

3 个答案:

答案 0 :(得分:0)

抱歉,我没有数据来测试这个。设置一个样本表并试一试。

但也许是这样的:

WITH abc_Order (n,period,WIP_Close,WIP_Open,WIP_Add,WIP_Minus) AS (
    select
    ROW_NUMBER() OVER(
        ORDER BY
            period
    ) n,
    n,period,WIP_Close,WIP_Open,WIP_Add,WIP_Minus
    from abc
)
update curr
set
    WIP_Open = prev.WIP_Close,
    WIP_Close = prev.WIP_Close + curr.WIP_Add - curr.WIP_Minus
from abc_Order curr
inner join abc_Order prev on
    curr.n = prev.n+1

答案 1 :(得分:0)

让我们制作一些测试数据

DECLARE @MyTable TABLE
(
    Period int IDENTITY, 
    WIP_Open int, 
    WIP_Close int, 
    WIP_Add int, 
    WIP_Minus int
)

第一条记录具有默认的开放数据集。

INSERT INTO @MyTable
( WIP_Open, WIP_ADD, WIP_Minus )
VALUES
( 10, 1, 2 )

现在我们有一些加/卖库存的加/减

INSERT INTO @MyTable
( WIP_Add, WIP_Minus )
VALUES
( 2, 1 ),
( 5, 3 ),
( 6, 1 ),
( 1, 7 );

现在让我们总结所有的变化以及原始记录,以查看运行总计并获得每条记录的结束。

WITH T AS
(
    SELECT
        Period,
        WIP_Open,
        WIP_Add, 
        WIP_Minus,
        SUM(ISNULL(WIP_Open, 0) + WIP_Add - WIP_Minus) OVER (ORDER BY Period) RunningWipClose
    FROM @MyTable
)

SELECT * FROM T

这是输出:

Period  WIP_Open    WIP_Add WIP_Minus   RunningWipClose
1   10  1   2   9
2   NULL    2   1   10
3   NULL    5   3   12
4   NULL    6   1   17
5   NULL    1   7   11

在此之后,使用滞后函数将空打开设置为prev close。

答案 2 :(得分:0)

Input -
    period  WIP_Close   WIP_Open    WIP_Add WIP_Minus
    1   1   1   1   10
    2   8   3   7   5
    3   6   4   9   15

Output-   
period  WIP_Close   WIP_Open    WIP_Add WIP_Minus
1   1   1   1   10
2   3   1   7   5
3   -3  3   9   15

I guess you want to solve above problem.

Here is the solution.Let me know if you are not able to understand this.

 SELECT * INTO #T
    FROM
    (
    SELECT 1 period, 1 WIP_Close, 1  WIP_Open, 1 WIP_Add, 10 WIP_Minus UNION ALL
    SELECT 2 period, 8 WIP_Close, 3  WIP_Open, 7 WIP_Add, 5 WIP_Minus UNION ALL
    SELECT 3 period, 6 WIP_Close, 4  WIP_Open, 9 WIP_Add, 15 WIP_Minus ) TAB

    SELECT * FROM #T

    DECLARE @TopC INT = (SELECT TOP 1 WIP_Close FROM #T)
    DECLARE @TopO INT = (SELECT TOP 1 WIP_Open FROM #T)
    DECLARE @TopDIff INT = (SELECT TOP 1 WIP_Add - WIP_Minus FROM #T)


    SELECT period,
           @TopC + SUM(WIP_Add - WIP_Minus) OVER (ORDER BY  period ROWS BETWEEN  UNBOUNDED PRECEDING AND CURRENT ROW ) - @TopDIff AS WIP_Close,
           COALESCE(@TopC + SUM(WIP_Add - WIP_Minus) OVER (ORDER BY  period ROWS BETWEEN  UNBOUNDED PRECEDING AND 1 PRECEDING ) - @TopDIff,@TopO) AS WIP_Open,
           WIP_Add,
           WIP_Minus
    FROM #T