来自当前和之前日期的累积列值

时间:2011-03-27 14:42:51

标签: sql sql-server tsql

我有一张注册表,大约有300K记录。我需要一个SQL语句来显示该特定日期的注册总数吗?

select
count('x'),CONVERT(varchar(12),date_created,111)
from reg group by
cONVERT(varchar(12),date_created,111)
order by
CONVERT(varchar(12),date_created,111)

此查询的结果:

169      2011/03/24
3016     2011/03/25
2999     2011/03/26

期望的结果:

 2011/03/25  3016+169
 2011/03/26  2999+3016+169

如何做到这一点?

6 个答案:

答案 0 :(得分:2)

只需使用SUM即可获得累积计数:

SELECT reg1.date_created,       
       SUM(reg2.val) AS CumulativeValue
FROM (
       select count(*) as RegCountForDay,
              date_created
       from  reg 
       group by  date_created
     )  AS reg1
LEFT JOIN reg AS reg2 ON (reg2.date_created <= reg1.date_created)
GROUP BY reg1.date_created

答案 1 :(得分:2)

目前您有两个选择:第一个是使用vbence建议的连接,第二个是子查询:

SELECT r1.date_created, (SELECT COUNT(*) FROM reg r2 
WHERE r2.date_created<=r1.date_created) AS total_num
FROM reg r1;

这两种方法产生类似的执行计划。

将来,当SQLServer使用聚合函数为ORDER BY实现OVER时,您将能够编写

SELECT date_created, 
COUNT(*) OVER(ORDER BY date_created) as total_num
FROM reg;

答案 2 :(得分:2)

这是两个版本。我已经在一台速度非常慢的计算机上测试了超过6000天的100000行,内存不足,这表明cte版本比循环版本更快。这里建议的其他版本(到目前为止)要慢得多,前提是我已正确理解了问题。

递归CTE (10秒)

-- Table variable to hold count for each day
declare @DateCount table(d int, c int, rn int)
insert into @DateCount
  select 
    datediff(d, 0, date_created) as d,
    count(*) as c,
    row_number() over(order by datediff(d, 0, date_created)) as rn
  from reg
  group by datediff(d, 0, date_created)

-- Recursive cte using @DateCount to calculate the running sum
;with DateSum as
(
  select 
    d, c, rn
  from @DateCount
  where rn = 1
  union all
  select 
    dc.d, ds.c+dc.c as c, dc.rn
  from DateSum as ds
    inner join @DateCount as dc
      on ds.rn+1 = dc.rn  
)
select
  dateadd(d, d, 0) as date_created,
  c as total_num
from DateSum
option (maxrecursion 0)

循环(14秒)

-- Table variable to hold count for each day
declare @DateCount table(d int, c int, rn int, cr int)
insert into @DateCount
  select 
    datediff(d, 0, date_created) as d,
    count(*) as c,
    row_number() over(order by datediff(d, 0, date_created)) as rn,
    0
  from reg
  group by datediff(d, 0, date_created)

declare @rn int = 1

-- Update cr with running sum
update dc set
  cr = dc.c  
from @DateCount as dc
where rn = @rn

while @@rowcount = 1
begin
  set @rn = @rn + 1

  update dc set
    cr = dc.c + (select cr from @DateCount where rn = @rn - 1)  
  from @DateCount as dc
  where rn = @rn
end

-- Get the result
select
  dateadd(d, d, 0) as date_created,
  cr as total_num
from @DateCount

编辑1真正快速的版本

The quirky update

-- Table variable to hold count for each day
declare @DateCount table(d int primary key, c int, cr int)
insert into @DateCount
  select 
    datediff(d, 0, date_created) as d,
    count(*) as c,
    0
  from reg
  group by datediff(d, 0, date_created)

declare @rt int = 0
declare @anchor int

update @DateCount set
  @rt = cr = @rt + c,
  @anchor = d
option (maxdop 1)

-- Get the result
select
  dateadd(d, d, 0) as date_created,
  cr as total_num
from @DateCount                
order by d

答案 3 :(得分:1)

试试这个。

SELECT r1.date_created,
    COUNT(*) AS number
FROM (SELECT distinct(date_created) FROM reg) AS r1
    LEFT JOIN reg AS r2 ON (r2.date_created <= r1.date_created)
GROUP BY r1.date_created

当然,您必须使用以下内容对表进行索引:

CREATE INDEX datefilter ON reg (date_created);

答案 4 :(得分:1)

你可以通过下面的sql查询来解决这个问题。你给了两列col1=Numbercol2=Date

Select DATE,OUTPUT=SUM(InnerValue) from
(
  Select T1.Date, T1.Number, InnerValue=ISNULL(T2.Number,0)  from
  (
   Select ID=DENSE_RANK() OVER(ORDER BY DATE),Date,Number from YourTable
  ) As T1
  LEFT JOIN
  (
   Select ID=DENSE_RANK() OVER(ORDER BY DATE),Date,Number from YourTable
  ) AS T2
  ON T1.ID >= T2.ID
) As MainTable GROUP BY DATE

答案 5 :(得分:0)

另一种选择是使用CLR定义您自己的运行总和函数,如以下链接中所述:

http://pavelpawlowski.wordpress.com/2010/09/30/sql-server-and-fastest-running-totals-using-clr/