2012-08-16 31 views
5

Tôi có một bảng đơn giản với một số thiết lập dữ liệu giả như:T-SQL sử dụng SUM cho một chạy tổng

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

tôi có thể chọn một số hoạt động bằng cách thực hiện sql sau (MSSQL 2008) tuyên bố:

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 

Điều này sẽ cho tôi kết quả như:

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

Bây giờ là nó có thể chỉ lấy hàng gần đây nhất cho ea ch người dùng? Vì vậy, kết quả sẽ là:

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

Tôi có làm đúng cách này không? bất kỳ đề xuất hoặc một con đường mới để làm theo sẽ là tuyệt vời!

+3

Bạn chỉ quan tâm đến kết quả cuối cùng hay bạn cũng cần tổng số đang chạy? Bạn đang lưu trữ tổng số đang chạy ở đâu đó, hoặc bạn đang sử dụng nó Chỉ để tạo kết quả cuối cùng của bạn? * [Kết quả cuối cùng của bạn có thể được tạo hiệu quả hơn mà không cần sử dụng tổng số đang chạy. Tuy nhiên, nếu bạn đã có tổng số đang chạy được lưu trữ ở đâu đó, vì các lý do khác, nó có thể được sử dụng.] * – MatBailie

+0

Bạn đã thay đổi câu trả lời được chấp nhận để cải thiện hiệu suất, nhưng bạn chưa trả lời truy vấn của tôi ở trên. Lưu ý rằng bạn có thể cải thiện hiệu suất bằng cách không *** bằng cách sử dụng phương pháp tổng chạy. Điều đó có được bạn quan tâm không, hoặc bạn có cần tất cả kết quả trong tổng số hoạt động * không? *? – MatBailie

+0

Hi Dems, tôi đã bận rộn làm việc và bỏ lỡ bình luận của bạn. Tôi chỉ sau tổng số và người dùng có liên quan, vì vậy vâng tôi quan tâm đến hiệu suất được cải thiện. – luke2012

Trả lời

5

thử điều này:

;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

Cảm ơn, điều này cũng hoạt động với hiệu suất tốt hơn! – luke2012

+0

@Joe G Joseph, có vẻ như liên kết tới SQL Fiddle bị hỏng. – rstackhouse

+0

Điều này cũng sẽ không hoạt động trên SQL Server 2008. – rstackhouse

1

add nơi tuyên bố:

select * from 
(
your select statement 
) t 

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

bạn cũng có thể sử dụng truy vấn này:

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

Cảm ơn rất nhiều, hoạt động tuyệt vời! – luke2012

0

Thêm quyền tham gia sẽ thực hiện tốt hơn so với lồng chọn.

Hoặc thậm chí đơn giản hơn:

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

Nhưng tối đa (id) và giá trị (tối đa) có thể từ các hàng trong bảng gốc khác nhau. – valex

+0

-1: Đây là cách tiếp cận đơn giản mà không hoạt động chính xác. Bạn không thể giả định rằng MAX (id) và MAX (giá trị) cho kết quả từ cùng một hàng đầu vào. – MatBailie

+0

Bạn nói đúng, tôi nhận ra sau khi đăng. Nhưng vẫn còn, một tham gia quyền thông minh sẽ thực hiện tốt hơn so với chọn lồng nhau. –

9

Không tham gia là cần thiết, bạn có thể tăng tốc độ truy vấn theo cách này:

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: Hoàn toàn tránh đề xuất lạ về việc sử dụng tổng số chạy ... – MatBailie

+0

điều này có thể được đẩy nhanh hơn nữa bằng cách nêu rõ các đối số bổ sung cho mệnh đề trên của 'SUM OVER' – whytheq

0

Compati ble với SQL Server 2008 hoặc mới hơn

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 
Các vấn đề liên quan