2011-03-27 16 views
8

que tienen una tabla de registros, alrededor de 300K registros. Necesito una declaración SQL que muestre la cantidad total de registros para ese día en particular.valores de columna acumulativos de las fechas actuales y anteriores

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) 

resultado de esta consulta:

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

los resultados deseados:

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

¿Cómo puede hacerse esto?

+0

Oh, veo [sql-server] está reservada para MS: o muy engañoso. – vbence

+0

@vbence: Parece que no has oído hablar de SQL Server. http://en.wikipedia.org/wiki/Microsoft_SQL_Server –

+0

@ p.campbell Wow ... tanta hostilidad en un comentario tan breve. – vbence

Respuesta

2

Aquí hay dos versiones de hacer esto. He probado con 100000 filas, repartidas en 6.000 días en un ordenador muy lento con suficiente memoria, y que muestra que la versión CTE es más rápido que la versión de bucle. Las otras versiones sugeridas aquí (hasta ahora) es mucho más lento, con la condición de que he entendido el problema correctamente.

CTE recursiva (10 segundos)

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

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

Edición 1 La versión muy rápido

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

+1 La peculiar técnica de actualización es la más rápida. ¡Simplemente no está documentada ni garantizada! Al menos debería tener al menos un índice agrupado y un conjunto 'MAXDOP 1' establecido (como se discutió aquí http://www.sqlservercentral.com/articles/T-SQL/68467/) –

+0

@Martin -" No documentado o garantizado "podría ser una razón válida para elegir la versión cte recursiva más lenta en cambio si el rendimiento es razonable. Quizás la actualización puede fallar porque el orden de la actualización no está garantizado. Sería malo si comenzara a hacer actualizaciones desde la parte inferior o si SQL Server hace una elección para ejecutar la actualización en paralelo. No tengo idea si eso es probable que suceda. Voy a probar esto mañana en el trabajo, donde tengo una computadora con más de un procesador :). –

+1

@Martin - No leí su comentario editado antes de publicar el mío. El índice agrupado y 'maxdop 1' suena como la solución a las cosas que me preocupaban. –

1

prueba este.

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 

Por supuesto que tiene que indexar su mesa con algo como:

CREATE INDEX datefilter ON reg (date_created); 
+0

esto es incorrecto; no produce un valor acumulativo. –

+0

Le daría el número de registros para un día determinado y para todos los días anteriores combinados. Esto es tan acumulativo como se pone. – vbence

+0

Así es como se ven los resultados de su consulta: http://i.imgur.com/VLdrT.png –

2

Sólo tiene que utilizar un SUM para obtener un recuento acumulativo:

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

Creo que esto daría exactamente el mismo resultado que las dos respuestas precarias. – vbence

+0

@vbence: inicie SQL Management Studio, pegue esta respuesta y ejecútela. Es SUM'ing en 'r2', no' r1'. –

+0

En ese momento asumí que el mío también dio los resultados correctos. :) – vbence

2

Actualmente tiene 2 opciones: primero es el uso de unirse a la forma propuesta por vbence, segundo es subconsulta:

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

Estos 2 enfoques generan planes de ejecución similares.

En el futuro, cuando SQL Server implementa ORDER BY para OVER con funciones de agregado, usted será capaz de escribir

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

3 opciones - La tercera está usando un cursor, o [la CLR para actuar como un cursor más rápido] (http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/running-sums-yet -again-sqlclr-saves-the-day.aspx) –

+0

@Martin: Claro, puedes obtener los mismos resultados con los cursores, pero los cursores tienen un rendimiento general, por lo que no los usaría en esos casos ... – a1ex07

+1

Depende de cuántos las filas necesitan ser procesadas. La carga de trabajo de combinación triangular crece proporcionalmente al cuadrado de la cantidad de filas. El cursor se carga linealmente. –

1

puede resolver este problema a través de la consulta SQL a continuación ..Usted ha dado dos columnas col1=Number y 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 
Cuestiones relacionadas