基于某个类别的前 n 个列的总和

use*_*927 6 sql-server aggregate t-sql window-functions

我有以下输入,我需要计算每个类别前 x 周数的值的总和。

输入

如果 x 为 3,输出将如下所示:

在此处输入图片说明

请注意,最后一个值为 49,因为自 x=3 以来,它仅将上周的值添加到当前周。

我希望将 SQL 编写为存储过程,并且需要一些有关执行此操作的适当方法的帮助。

在@sp_BlitzErik 的帮助下,我尝试使用LAG,但无法完全到达我需要的地方。这是我的查询:

SELECT category
    ,year
    ,week
    ,value
    ,(
        LAG(value, 1, 0) OVER (
            ORDER BY category
                ,year
                ,week
            ) + LAG(value, 2, 0) OVER (
            ORDER BY category
                ,year
                ,week
            ) + value
        ) AS cumulative_value
FROM valuedata
Run Code Online (Sandbox Code Playgroud)

输出还不太正确:

在此处输入图片说明

joa*_*olo 5

在 SQL Server 2014 和 2016 1 上,您可以使用WINDOW函数(即OVER子句)来执行您想要的操作:

SELECT
     category, year, week, value, 
     sum(value) OVER (PARTITION BY category 
                          ORDER BY year, week 
                              ROWS 2 PRECEDING) AS retention_value_3_weeks
FROM
     t 
ORDER BY
    category, year, week ;
Run Code Online (Sandbox Code Playgroud)

这是你会得到的结果:

类别 | 年 | 一周 | 价值 | 保留价值_3_周
:------- | ---: | ---: | ----: | ---------------:
| 2016 | 1 | 5 | 5
| 2016 | 2 | 7 | 12
| 2016 | 3 | 8 | 20
乙 | 2016 | 3 | 6 | 6
乙 | 2016 | 4 | 15 | 21
乙 | 2016 | 5 | 25 | 46
| | 2016 | 3 | 25 | 25
| | 2016 | 4 | 2 | 27
| | 2016 | 5 | 21 | 48
| | 2016 | 6 | 26 | 49

请注意,x = 3您的示例的 被转换为(当前行2 preceding那些)。

如果由于某种原因,您不能使用该OVER子句,您仍然可以使用一些(相当复杂的)子查询来计算相同的结果:

SELECT
    category, year, week, value,
    (SELECT 
        sum(value)
     FROM
        (SELECT TOP 3                    /* total number of rows to consider */
             value
        FROM 
           t t2
        WHERE
               t2.category = t.category  /* partition by category */
           AND t2.week <= t.week         /* current and preceding rows */
        ORDER BY
           year DESC, week DESC          /* order by criteria */
        ) AS q
     ) AS retention_value_3_weeks
FROM
    t 
ORDER BY
    category, year, week ;
Run Code Online (Sandbox Code Playgroud)

此处的dbfiddle 中查看所有内容

如果你想使用@x而不是3,你可以这样做:

DECLARE @x AS INTEGER = 3;

SELECT
    category, year, week, value,
    (SELECT 
        sum(value)
     FROM
        (SELECT TOP (@x)                  /* total number of rows to consider */
             value
        FROM 
           t t2
        WHERE
               t2.category = t.category  /* partition by category */
           AND t2.week <= t.week         /* current and preceding rows */
        ORDER BY
           year DESC, week DESC          /* order by criteria */
        ) AS q
     ) AS retention_value_3_weeks
FROM
    t 
ORDER BY
    category, year, week ;;
Run Code Online (Sandbox Code Playgroud)

dbfiddle在这里


1)无法使用 SQL Server 2012 进行测试,因为我没有。MS SQL Server 的文档表明它应该从 2008 版开始可用。