Накопительные значения столбцов по датам текущего и предыдущего - PullRequest
8 голосов
/ 27 марта 2011

У меня есть таблица регистраций, около 300К записей. Мне нужен оператор 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 ]

2 голосов
/ 28 марта 2011

Вот две версии для этого.Я протестировал 100000 строк, распределенных за 6000 дней, на очень медленном компьютере с недостаточным объемом памяти, и это показывает, что версия 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 Действительно быстрая версия

Причудливое обновление

-- 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
2 голосов
/ 27 марта 2011

В настоящее время у вас есть 2 варианта: первый использует объединение в соответствии с предложением vbence, второй - подзапрос:

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

Эти 2 подхода генерируют аналогичные планы выполнения.

В будущем, когда SQLServer реализует ORDER BY для OVER с агрегатными функциями, вы сможете написать

SELECT date_created, 
COUNT(*) OVER(ORDER BY date_created) as total_num
FROM reg;
2 голосов
/ 27 марта 2011

Просто используйте 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 голос
/ 14 декабря 2012

Вы можете решить эту проблему с помощью SQL-запроса ниже. Вы дали два столбца col1=Number и 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
1 голос
/ 27 марта 2011

Попробуйте это.

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);
0 голосов
/ 28 марта 2011

Другой вариант - использовать CLR для определения собственной функции промежуточной суммы, как описано в следующей ссылке:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...