2012-09-04 34 views
0

我有一張表,我想爲每個行ID找到剩餘總量。但是,金額的順序是按升序排列的。如何計算每行的剩餘金額?

id amount 
1 3 
2 2 
3 1 
4 5 

結果應該是這樣的:

id remainder 
1 10 
2 8 
3 5 
4 0 

如何做到這一點有什麼想法?我猜測,過分的條款是要走的路,但我不能把它拼在一起。謝謝。

+5

請添加一個標識符,用於標識您使用的特定rdbms –

回答

-1

SQL Server 2008中的回答,我不能提供一個SQL小提琴,現在看來,這條的begin關鍵字,從而提高對語法錯誤。不過,我覺得這個測試我的機器上:

create function RunningTotalGuarded() 
returns @ReturnTable table(
    Id int, 
    Amount int not null, 
    RunningTotal int not null, 
    RN int identity(1,1) not null primary key clustered 
) 

as 
begin 

    insert into @ReturnTable(id, amount, RunningTotal) 
    select id, amount, 0 from tbl order by amount; 

    declare @RunningTotal numeric(16,4) = 0; 
    declare @rn_check int = 0; 

    update @ReturnTable 
    set 
     @rn_check = @rn_check + 1 
     ,@RunningTotal = 
     case when rn = @rn_check then 
      @RunningTotal + Amount 
     else 
      1/0 
     end 
     ,RunningTotal = @RunningTotal;  
    return;  
end; 

爲了達到所需輸出:

with a as 
(
    select *, sum(amount) over() - RunningTotal as remainder 
     , row_number() over(order by id) as id_order 
    from RunningTotalGuarded() 
) 
select a.id, amount_order.remainder 
from a 
inner join a amount_order on amount_order.rn = a.id_order; 

理由把守運行總計:http://www.ienablemuch.com/2012/05/recursive-cte-is-evil-and-cursor-is.html

選擇兩害取其輕;-)

+0

我會考慮它。謝謝你給我看這個。我很想知道,如果我想使用光標並通過表中的另一個ID拆分總數,我該如何實現這一目標? – user1281598

2

既然你沒有指定你的RDBMS,我只是假設它是PostgreSQL的;-)

select *, sum(amount) over() - sum(amount) over(order by amount) as remainder 
from tbl; 

輸出:

| ID | AMOUNT | REMAINDER | 
--------------------------- 
| 3 |  1 |  10 | 
| 2 |  2 |   8 | 
| 1 |  3 |   5 | 
| 4 |  5 |   0 | 

工作原理:http://www.sqlfiddle.com/#!1/c446a/5

它工作在SQL Server 2012太:http://www.sqlfiddle.com/#!6/c446a/1

思考s解決方案SQL Server 2008 ...


順便說一句,你的ID只是一個行號?如果是這樣,只是這樣做:

select 
    row_number() over(order by amount) as rn 
    , sum(amount) over() - sum(amount) over(order by amount) as remainder 
from tbl 
order by rn; 

輸出:

| RN | REMAINDER | 
------------------ 
| 1 |  10 | 
| 2 |   8 | 
| 3 |   5 | 
| 4 |   0 | 

但如果你真的需要的ID完整和移動在頂部的最小量,這樣做:

with a as 
(
    select *, sum(amount) over() - sum(amount) over(order by amount) as remainder, 
     row_number() over(order by id) as id_sort, 
     row_number() over(order by amount) as amount_sort 
    from tbl 
) 
select a.id, sort.remainder 
from a 
join a sort on sort.amount_sort = a.id_sort 
order by a.id_sort; 

輸出:

| ID | REMAINDER | 
------------------ 
| 1 |  10 | 
| 2 |   8 | 
| 3 |   5 | 
| 4 |   0 | 

查看查詢進程裂變這裏:http://www.sqlfiddle.com/#!6/c446a/11

+0

我實際上忽略了另一個規範:我正在通過外部密鑰對這些數量進行排序。將會有另一個整數ID來分割它們。很重要的是忘記我知道的,但能夠在CTE中使用它解決了我的問題的另一部分。謝謝。 – user1281598

1

我只是想提供一個更簡單的方式按降序爲了做到這一點:

select id, sum(amount) over (order by id desc) as Remainder 
from t 

這將在甲骨文,SQL Server 2012中,和Postgres工作。

的通解requres自連接:

select t.id, coalesce(sum(tafter.amount), 0) as Remainder 
from t left outer join 
    t tafter 
    on t.id < tafter.id 
group by t.id 
+0

在100行上運行總數相當於硬盤盤片的5,050轉。對於1,000行,它更加指數級,相當於硬盤盤片的500,500轉;-) http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/running-sums-redux.aspx –

+0

@ MichaelBuen。 。 。是的我同意。所有的數據庫供應商都應該支持所有的窗口功能。 –

+0

說如果我想用桌子上的另一個ID進行排序,是使用where子句將它分配給我還是必須使用該id值進行分區? – user1281598