2012-08-16 17 views
5

Tengo una tabla sencilla total acumulado con algún tipo de configuración de datos ficticios como:T-SQL con SUM para un

|id|user|value| 
--------------- 
1 John 2 
2 Ted 1 
3 John 4 
4 Ted 2 

puedo seleccionar un total acumulado ejecutando el siguiente sql (MSSQL 2008) declaración:

SELECT a.id, a.user, a.value, SUM(b.value) AS total 
FROM table a INNER JOIN table b 
ON a.id >= b.id 
AND a.user = b.user 
GROUP BY a.id, a.user, a.value 
ORDER BY a.id 

Esto me dará resultados como:

|id|user|value|total| 
--------------------- 
1 John 2  2 
3 John 4  6 
2 Ted 1  1 
4 Ted 2  3 

Ahora es posible recuperar sólo los más recientes filas de EA ch usuario? Entonces, el resultado sería:

|id|user|value|total| 
--------------------- 
3 John 4  6 
4 Ted 2  3 

¿Estoy haciendo esto de la manera correcta? cualquier sugerencia o un nuevo camino a seguir sería genial!

+3

¿Está interesado únicamente en el resultado final, o necesita el total acumulado también? ¿Ya está almacenando ese total acumulado en alguna parte, o lo está usando solo para generar su resultado final? * [Su resultado final se puede crear de manera más efectiva sin usar un total acumulado. Pero, si ya tiene el total acumulado almacenado en alguna parte, por otros motivos, sin duda puede usarse.] * – MatBailie

+0

Usted configuró su respuesta aceptada para mejorar el rendimiento, pero no ha respondido a mi consulta anterior. Tenga en cuenta que puede mejorar el rendimiento por *** no *** utilizando el método de total acumulado. ¿Le interesaría eso o necesita todos los resultados en total * también *? – MatBailie

+0

Hola demócratas, estuve muy ocupado trabajando y perdí tu comentario. Solo busco el total y el usuario asociado, entonces sí, estoy interesado en un mejor rendimiento. – luke2012

Respuesta

5

intente esto:

;with cte as 
    (SELECT a.id, a.[user], a.value, SUM(b.value) AS total 
    FROM users a INNER JOIN users b 
    ON a.id >= b.id 
    AND a.[user] = b.[user] 
    GROUP BY a.id, a.[user], a.value 
    ), 
cte1 as (select *,ROW_NUMBER() over (partition by [user] 
         order by total desc) as row_num 
     from cte) 
select id,[user],value,total from cte1 where row_num=1 

SQL Fiddle Demo

+0

¡Gracias, esto también funciona con un mejor rendimiento! – luke2012

+0

@Joe G Joseph, parece que el enlace al SQL Fiddle está roto. – rstackhouse

+0

Esto tampoco funcionará en SQL Server 2008. – rstackhouse

1

complemento donde declaración:

select * from 
(
your select statement 
) t 

where t.id in (select max(id) from table group by user) 

También se puede utilizar esta consulta:

SELECT a.id, a.user, a.value, 

(select max(b.value) from table b where b.user=a.user) AS total 

FROM table a 

where a.id in (select max(id) from table group by user) 

ORDER BY a.id 
+0

Muchas gracias, funciona genial! – luke2012

0

Adición de un derecho unirse realizaría mejor que anidado de selección.

O aún más simple:

SELECT MAX(id), [user], MAX(value), SUM(value) 
FROM table 
GROUP BY [user] 
+0

Pero max (id) y max (value) pueden ser de diferentes filas de tabla originales. – valex

+0

-1: este es un enfoque simplificado que simplemente no funciona correctamente. No puede suponer que MAX (id) y MAX (valor) dan resultados de la misma fila de entrada. – MatBailie

+0

Tienes razón, me di cuenta después de publicar. Pero aún así, una combinación inteligente correcta tendría un mejor rendimiento que la selección anidada. –

9

Sin JOIN es necesario, se puede acelerar la consulta de esta manera:

select id, [user], value, total 
from 
(
    select id, [user], value, 
    row_number() over (partition by [user] order by id desc) rn, 
    sum(value) over (partition by [user]) total 
from users 
) a 
where rn = 1 
+3

+1: evita por completo la extraña sugerencia de utilizar un total runing ... – MatBailie

+0

esto se puede acelerar aún más declarando explícitamente los argumentos adicionales a la cláusula de "SUM OVER" – whytheq

0

Compati con SQL Server 2008 o posterior

DECLARE @AnotherTbl TABLE 
    (
     id   INT 
     , somedate  DATE 
     , somevalue DECIMAL(18, 4) 
     , runningtotal DECIMAL(18, 4) 
    ) 

INSERT INTO @AnotherTbl 
    (
     id 
     , somedate 
     , somevalue 
     , runningtotal 
    ) 
SELECT LEDGER_ID 
     , LL.LEDGER_DocDate 
     , LL.LEDGER_Amount 
     , NULL 
FROM ACC_Ledger LL 
ORDER BY LL.LEDGER_DocDate 

DECLARE @RunningTotal DECIMAL(18, 4) 
SET @RunningTotal = 0 

UPDATE @AnotherTbl 
SET @RunningTotal=runningtotal = @RunningTotal + somevalue 
FROM @AnotherTbl 

SELECT * 
FROM @AnotherTbl