开发者

Cumulative column values from dates current and previous

开发者 https://www.devze.com 2023-02-19 21:37 出处:网络
I have a table of registrations, around 300K records. I need a SQL statement that will show the total number of registrations for that particular day?

I have a table of registrations, around 300K records. I need a SQL statement that will show the total number of registrations for that particular day?

select
count('x'),CONVERT(varc开发者_StackOverflowhar(12),date_created,111)
from reg group by
cONVERT(varchar(12),date_created,111)
order by
CONVERT(varchar(12),date_created,111)

Result of this query:

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

Desired outcome:

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

How can this be done?


Here is two versions to do this. I have tested with 100000 rows spread over 6000 days on a really slow computer with not enough memory, and that shows that the cte version is faster than the loop version. The other versions suggested here (so far) is a lot slower, provided that I have understood the problem correctly.

Recursive CTE (10 seconds)

-- 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)

Loop (14 seconds)

-- 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

Edit 1 The really fast version

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


Currently you have 2 options: first is using join as proposed by vbence, second is subquery :

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

These 2 approaches generate similar execution plans.

In the future, when SQLServer implements ORDER BY for OVER with aggregate functions, you will be able to write

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


Simply use a SUM to get a cumulative count:

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


Try this one.

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

Of course you have to index your table with something like:

CREATE INDEX datefilter ON reg (date_created);


you can solve this problem through below sql query..You have given two columns col1=Number and col2=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


Another option is to use CLR to define your own Running Sum Function as described in the followig link:

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

0

精彩评论

暂无评论...
验证码 换一张
取 消