Como sugiere el título, necesito ayuda para obtener un total acumulado en T-SQL. El problema es que la suma que necesito hacer es la suma de un conteo:
sum(count (distinct (customers)))
Digamos que si ejecuté el conteo solo, el resultado sería:
Day | CountCustomers
----------------------
5/1 | 1
5/2 | 0
5/3 | 5
Necesito salida con la suma para ser:
Day | RunningTotalCustomers
----------------------
5/1 | 1
5/2 | 1
5/3 | 6
He hecho totales antes de usar el coalesce
método, pero nunca con un conteo. No estoy seguro de cómo hacerlo ahora que tengo la cuenta.
sql-server
t-sql
Aaron Bertrand
fuente
fuente
Day
una clave y los valores son contiguos?Respuestas:
Aquí hay algunos métodos que puede comparar. Primero, configuremos una tabla con algunos datos ficticios. Estoy completando esto con un montón de datos aleatorios de sys.all_columns. Bueno, es algo aleatorio: me aseguro de que las fechas sean contiguas (lo que en realidad solo es importante para una de las respuestas).
Resultados:
Los datos se ven así (5000 filas), pero se verán ligeramente diferentes en su sistema según la versión y el número de compilación:
Y los resultados de los totales acumulados deberían verse así (501 filas):
Entonces, los métodos que voy a comparar son:
auto-unirse
Esta es la forma en que la gente le dirá que lo haga cuando le adviertan que se mantenga alejado de los cursores, porque "basado en conjuntos siempre es más rápido". En algunos experimentos recientes, descubrí que el cursor supera esta solución.
cte recursivo con fechas
Recordatorio: esto se basa en fechas contiguas (sin espacios), hasta 10000 niveles de recursión, y que conoce la fecha de inicio del rango que le interesa (para establecer el ancla). Podría establecer el ancla dinámicamente utilizando una subconsulta, por supuesto, pero quería mantener las cosas simples.
cte recursivo con row_number
El cálculo del número de fila es un poco caro aquí. Nuevamente, esto admite un nivel máximo de recursión de 10000, pero no es necesario asignar el ancla.
cte recursivo con tabla temporal
Robando la respuesta de Mikael, como se sugiere, para incluir esto en las pruebas.
actualización peculiar
Nuevamente, solo incluyo esto para completar; Personalmente, no confiaría en esta solución ya que, como mencioné en otra respuesta, no se garantiza que este método funcione en absoluto, y puede romperse por completo en una versión futura de SQL Server. (Estoy haciendo todo lo posible para obligar a SQL Server a obedecer el orden que quiero, usando una pista para la elección del índice).
cursor
"¡Cuidado, hay cursores aquí! ¡Los cursores son malvados! ¡Debes evitar los cursores a toda costa!" No, no soy yo quien habla, son cosas que escucho mucho. Contrariamente a la opinión popular, hay algunos casos en que los cursores son apropiados.
SQL Server 2012
Si está utilizando la versión más reciente de SQL Server, las mejoras en la funcionalidad de ventanas nos permiten calcular fácilmente los totales acumulados sin el costo exponencial de la unión automática (el SUM se calcula en una pasada), la complejidad de los CTE (incluido el requisito de filas contiguas para el mejor rendimiento de CTE), la actualización peculiar no compatible y el cursor prohibido. Solo tenga cuidado con la diferencia entre usar
RANGE
yROWS
, o no especificar, soloROWS
evita un carrete en el disco, lo que obstaculizará significativamente el rendimiento de lo contrario.comparaciones de rendimiento
Tomé cada enfoque y lo envolví un lote usando lo siguiente:
Estos son los resultados de la duración total, en milisegundos (recuerde que esto también incluye los comandos DBCC cada vez):
Y lo hice nuevamente sin los comandos DBCC:
Eliminando tanto el DBCC como los bucles, solo mide una iteración sin procesar:
Por último, he multiplicado el número de filas en la tabla de origen por 10 (cambiando superior a 50.000 y la adición de otra tabla como una combinación cruzada). Los resultados de esto, una sola iteración sin comandos DBCC (simplemente en interés del tiempo):
Sólo mide la duración - Lo dejo como ejercicio para el lector comparar estos enfoques de sus datos, comparando otras métricas que pueden ser importantes (o pueden variar con su esquema / datos). Antes de sacar conclusiones a partir de esta respuesta, que será hasta usted para probarlo en contra de sus datos y su esquema ... estos resultados es casi seguro que cambian a medida que los recuentos de filas de llegar más alto.
manifestación
He agregado un sqlfiddle . Resultados:
conclusión
En mis pruebas, la elección sería:
Pero de nuevo, debe probarlos contra su esquema y datos. Dado que esta fue una prueba artificial con recuentos de filas relativamente bajos, también podría ser un pedo en el viento. He realizado otras pruebas con diferentes esquemas y recuentos de filas, y las heurísticas de rendimiento fueron bastante diferentes ... por eso hice tantas preguntas de seguimiento a su pregunta original.
ACTUALIZAR
He blogueado más sobre esto aquí:
Mejores enfoques para ejecutar totales: actualizado para SQL Server 2012
fuente
Esta es, aparentemente, la solución óptima.
fuente
day
por ejemplo.Solo otra forma, costosa, pero independiente de la versión. No usa tablas temporales o variables.
fuente