使用CTE提供累计总数

Rob*_*Dee 0 sql-server common-table-expression sql-server-2008 sql-server-2012

我有一张桌子上有一些名字:

SELECT * FROM d;

Forename
--------------------------------
Robert
Susan
Frances
Kate
May
Alex
Anna
Run Code Online (Sandbox Code Playgroud)

我想按字母顺序提取累计名称长度.到目前为止,我有:

WITH    Names ( RowNum, Forename, ForenameLength )
          AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY forename ) AS RowNum ,
                        Forename ,
                        LEN(forename) AS ForenameLength
               FROM     d
             )
    SELECT  RowNum ,
            Forename ,
            ForenameLength ,
            ISNULL(ForenameLength + ( SELECT    ISNULL(SUM(ForenameLength),0)
                                      FROM      Names
                                      WHERE     RowNum < n.RowNum
                                    ), 0) AS CumLen
    FROM    NAMES n;

RowNum               Forename                         ForenameLength CumLen
-------------------- -------------------------------- -------------- -----------
1                    Alex                             4              4
2                    Anna                             4              8
3                    Frances                          7              15
4                    Kate                             4              19
5                    May                              3              22
6                    Robert                           6              28
7                    Susan                            5              33
Run Code Online (Sandbox Code Playgroud)

但我明白应该可以在CTE中(递归地)执行此操作.谁知道如何实现这一目标?

NB虽然我们正在开发2012年,但目前的实时系统是2008年,所以任何解决方案都需要至少在短期内向后兼容.

Mik*_*son 5

您在SQL Server 2012上,应该使用它sum() over().

select row_number() over(order by d.Forename) as RowNum,
       d.Forename,
       len(d.Forename) as ForenameLength,
       sum(len(d.Forename)) over(order by d.Forename rows unbounded preceding) as CumLen
from d
order by d.Forename;
Run Code Online (Sandbox Code Playgroud)

结果:

RowNum   Forename     ForenameLength CumLen
-------- ------------ -------------- -----------
1        Alex         4              4
2        Anna         4              8
3        Frances      7              15
4        Kate         4              19
5        May          3              22
6        Robert       6              28
7        Susan        5              33
Run Code Online (Sandbox Code Playgroud)

更新:

如果你出于某种原因绝对想要一个递归版本,它可能看起来像这样:

with C as
(
  select top(1)
    1 as RowNum,
    d.Forename,
    len(d.Forename) as ForenameLength,
    len(d.Forename) as CumLen
  from d
  order by d.Forename      
  union all
  select d.RowNum,
         d.Forename,
         d.ForenameLength,
         d.CumLen      
  from (
       select C.RowNum + 1 as RowNum,
              d.Forename,
              len(d.Forename) as ForenameLength,
              C.CumLen + len(d.Forename) as CumLen,
              row_number() over(order by d.ForeName) as rn
       from d
         inner join C
           on C.Forename < d.Forename
       ) as d
  where d.rn = 1
)
select C.RowNum,
       C.Forename,
       C.ForenameLength,
       C.CumLen
from C;
Run Code Online (Sandbox Code Playgroud)

改编自Paul White 的整体查询计划.

  • @EvaldasBuinauskas是的,但我不明白为什么所以我会假设这是一个错字. (2认同)