Dynamic row range when calculating moving sum/average using window functions (SQL Server)

十年热恋 提交于 2019-12-10 15:13:05

问题


I'm currently working on a sample script which allows me to calculate the sum of the previous two rows and the current row. However, I would like to make the number '2' as a variable. I've tried declaring a variable, or directly casting in the query, yet a syntax error always pops up. Is there a possible solution?

DECLARE @myTable TABLE  (myValue INT)

INSERT INTO @myTable ( myValue ) VALUES  ( 5)
INSERT INTO @myTable ( myValue ) VALUES  ( 6)
INSERT INTO @myTable ( myValue ) VALUES  ( 7)
INSERT INTO @myTable ( myValue ) VALUES  ( 8)
INSERT INTO @myTable ( myValue ) VALUES  ( 9)
INSERT INTO @myTable ( myValue ) VALUES  ( 10)

SELECT 
    SUM(myValue) OVER (ORDER BY myValue 
                       ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
FROM @myTable

回答1:


DECLARE @test VARCHAR = 1
DECLARE @sqlCommand VARCHAR(1000)
DECLARE @myTable TABLE  (myValue INT)

INSERT INTO @myTable ( myValue ) VALUES  ( 5)
INSERT INTO @myTable ( myValue ) VALUES  ( 6)
INSERT INTO @myTable ( myValue ) VALUES  ( 7)
INSERT INTO @myTable ( myValue ) VALUES  ( 8)
INSERT INTO @myTable ( myValue ) VALUES  ( 9)
INSERT INTO @myTable ( myValue ) VALUES  ( 10)

SET @sqlCommand = 'SELECT SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN ' + @test + ' PRECEDING AND CURRENT ROW)
                  FROM #temp'

EXEC (@sqlCommand)



回答2:


You can try something like this which does not use dynamic SQL.

DECLARE @myTable TABLE  (myValue INT)

INSERT INTO @myTable ( myValue ) VALUES  ( 5)
INSERT INTO @myTable ( myValue ) VALUES  ( 6)
INSERT INTO @myTable ( myValue ) VALUES  ( 7)
INSERT INTO @myTable ( myValue ) VALUES  ( 8)
INSERT INTO @myTable ( myValue ) VALUES  ( 9)
INSERT INTO @myTable ( myValue ) VALUES  ( 10)


DECLARE @prev_records INT = 2

;WITH CTE as 
(
SELECT ROW_NUMBER() OVER(ORDER BY myValue) rn,myValue FROM @myTable
)
SELECT (SELECT  SUM(myValue) FROM CTE t2 WHERE t2.rn BETWEEN (t1.rn  - @prev_records) AND t1.rn )
FROM CTE t1

SUM(myValue) OVER() is best option however it does not allow you to pass previous N rows using a variable.




回答3:


If possible dispersion of the range variable is not very high, you can use simple CASE statement to switch between calculations

DECLARE @myTable TABLE  (myValue INT)

-- let's say it could be between 1 and 10
DECLARE @range int = 3;

INSERT INTO @myTable ( myValue ) VALUES  ( 5)
INSERT INTO @myTable ( myValue ) VALUES  ( 6)
INSERT INTO @myTable ( myValue ) VALUES  ( 7)
INSERT INTO @myTable ( myValue ) VALUES  ( 8)
INSERT INTO @myTable ( myValue ) VALUES  ( 9)
INSERT INTO @myTable ( myValue ) VALUES  ( 10)

SELECT 
    CASE @range
        WHEN 1 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
        WHEN 2 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
        WHEN 3 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
        WHEN 4 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 4 PRECEDING AND CURRENT ROW)
        WHEN 5 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 5 PRECEDING AND CURRENT ROW)
        WHEN 6 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
        WHEN 7 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 7 PRECEDING AND CURRENT ROW)
        WHEN 8 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 8 PRECEDING AND CURRENT ROW)
        WHEN 9 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 9 PRECEDING AND CURRENT ROW)
        WHEN 10 THEN SUM(myValue) OVER (ORDER BY myValue ROWS BETWEEN 10 PRECEDING AND CURRENT ROW)
    END
FROM @myTable


来源:https://stackoverflow.com/questions/29695746/dynamic-row-range-when-calculating-moving-sum-average-using-window-functions-sq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!