各行IDについて、合計から残っている量を見つけたいテーブルがあります。ただし、金額の昇順です。
id amount
1 3
2 2
3 1
4 5
結果は次のようになります。
id remainder
1 10
2 8
3 5
4 0
これを達成する方法について何か考えはありますか?オーバー句が道のりだと思いますが、うまくまとめることができません。ありがとうございます。
各行IDについて、合計から残っている量を見つけたいテーブルがあります。ただし、金額の昇順です。
id amount
1 3
2 2
3 1
4 5
結果は次のようになります。
id remainder
1 10
2 8
3 5
4 0
これを達成する方法について何か考えはありますか?オーバー句が道のりだと思いますが、うまくまとめることができません。ありがとうございます。
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
SQLServer2008のソリューションを考えています...
ところで、あなたの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
降順でこれを行うためのより簡単な方法を提供したいだけです。
select id, sum(amount) over (order by id desc) as Remainder
from t
これは、Oracle、SQL Server 2012、およびPostgresで機能します。
一般的な解決策には、自己結合が必要です。
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
SQL Server 2008の回答、SQL Fiddleを提供できません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
より少ない悪を選択してください;-)