2017-05-30 10 views
1

パフォーマンスを向上させるためにカーソルをSQLで削除します(ベストプラクティスとベストプラクティスの使用方法をカーソルなしで設定する必要があるため)。とにかくcursur SQLステートメントを削除します

は、私はこのようになります一時テーブルを持っている:

DECLARE @Value INT  
BEGIN  
DECLARE c_Value CURSOR FOR 
    SELECT NR 
    FROM ##TMP 
    WHERE Value = 0  
----    
OPEN c_Value   
FETCH NEXT FROM c_Value 
INTO @Value 

WHILE @@FETCH_STATUS = 0 
BEGIN   
    SELECT @Value = Value - Change 
    FROM ##TMP 
    WHERE NR = (Select MAX(NR) From ##TMP WHERE Value <> 0)     
        BEGIN     
         UPDATE ##TMP 
         SET Value = @Value 
         WHERE NR = (Select MAX(NR)+1 From ##TMP WHERE Value <> 0) 
        END      
     FETCH NEXT FROM c_Value 
      INTO @Value    
      END 

    CLOSE c_Value 
    DEALLOCATE c_Value  
END 

結果:

+------------+--------+-------+----+ 
|  Period | Change | Value | NR | 
+------------+--------+-------+----+ 
|  201705 |  7 | 26055 | 1 | 
|  201704 |  29 | 26048 | 2 | 
|  201703 | -92 | 26019 | 3 | 
|  201702 | -338 | 26111 | 4 | 
|  201701 |  81 | 26449 | 5 | 
|  201612 | 107 | 26368 | 6 | 
|  201611 |  72 | 26261 | 7 | 
|  201610 |  54 | 26189 | 8 | 
|  201609 |  64 | 26135 | 9 | 
|  201608 |  47 | 26071 | 10 | 
|  201607 |  23 | 26024 | 11 | 
|  201606 |  45 | 26001 | 12 | 
+------------+--------+-------+----+ 

をだから、どのように次のように

+------------+--------+-------+----+ 
|  Period | Change | Value | NR | 
+------------+--------+-------+----+ 
|  201705 |  7 | 26055 | 1 | 
|  201704 |  29 |  0 | 2 | 
|  201703 | -92 |  0 | 3 | 
|  201702 | -338 |  0 | 4 | 
|  201701 |  81 |  0 | 5 | 
|  201612 | 107 |  0 | 6 | 
|  201611 |  72 |  0 | 7 | 
|  201610 |  54 |  0 | 8 | 
|  201609 |  64 |  0 | 9 | 
|  201608 |  47 |  0 | 10 | 
|  201607 |  23 |  0 | 11 | 
|  201606 |  45 |  0 | 12 | 
+------------+--------+-------+----+ 

現在、カーソルが働きカーソルを使用せずにこの結果を達成することはできますか? CTEで試してみましたが、この結果は得られません。

+0

これは、集合演算によって解決することはできませんが、あなたはそれを解決するために、相関サブクエリ、窓関数や再帰CTEを使用することができます。試したCTEを表示してください。そこから構築することができます。 – Jayvee

+1

どのようなSQLバージョンですか? –

+0

あなたはこの記事を見てください:https://msdn.microsoft.com/en-us/library/ms189461(v=sql.110).aspx – tgr

答えて

1

最初に開始値を取得する必要があります。次に、あなたが開始値を変更することができSUM()累積を用い

SELECT [Value] as StartValue 
FROM Table1 
WHERE NR = 1 

は、あなたが各行

SQL DEMO

WITH CTE as (
    SELECT [Value] as StartValue 
    FROM Table1 
    WHERE NR = 1 
)  
SELECT T.*, 
     - SUM(CHANGE) OVER (ORDER BY [NR]) 
     + [CHANGE] as TotalChange, -- just for debug, dont need this.  
     CTE.StartValue 
     - SUM([CHANGE]) OVER (ORDER BY [NR]) 
     + [CHANGE] as NewValue 
FROM Table1 T 
CROSS JOIN CTE 

OUTPUT

ため[Change]値を無視する必要が気付きますenter image description here

+0

ありがとう、私はこのアプローチが大好きです。私は2008年を使用し、エラーメッセージが表示されます。パラレルデータウェアハウス(PDW)機能は有効になっていません。私は少し修正しようとします。 –

0

これはこれは、フリーハンドだったと解析できないかもしれないが、十分なあなたは近くに取得する必要のSQL Serverで導入されたウィンドウ関数2014

select period, 
change, 
NR = Row_Number() Over(Order by period), 
Value = Sum(Change) Over(Order by period rows unbounded preceding) 

を使用することによって解決することができます。

+1

「NR」は変更されません。そして、あなたが私の答えをチェックするなら、開始値に影響を与えるには 'Sum(change)'を使う必要があります。 –

1

SQL Server 2012の以降:

CREATE TABLE ##TMP (
    Period int 
,Change float 
,Value float 
,Nr int 
); 
INSERT INTO ##TMP VALUES 
(201705,  7 , 26055, 1) 
,(201704, 29 ,  0, 2) 
,(201703, -92 ,  0, 3) 
,(201702, -338 ,  0, 4) 
,(201701, 81 ,  0, 5) 
,(201612, 107 ,  0, 6) 
,(201611, 72 ,  0, 7) 
,(201610, 54 ,  0, 8) 
,(201609, 64 ,  0, 9) 
,(201608, 47 ,  0,10) 
,(201607, 23 ,  0,11) 
,(201606, 45 ,  0,12) 

;with cte as (
SELECT Period, Change, value as Value_Org, Nr, SUM(Value - Change) OVER (ORDER BY Nr ASC) as Value 
FROM ##TMP 
) 
select a.Period, a.Change, a.nr, a.value_org, a.value, b.value, 
isnull(b.value, a.value_org) 
from cte as a 
left outer join cte as b 
on a.nr = b.nr+1 
order by a.Nr 
関連する問題