Reputation: 75
I have a table
id | amount
---+--------
1 | 500
2 | 300
3 | 750
4 | 200
5 | 500
I want to select rows ascending until the sum is 1000 or until all rows are searched (and skip a big value (750) that can exceed 1000).
How can I do query to return some rows like below?
Thanks for help
id | amount
---+--------
1 | 500
2 | 300
4 | 200
Upvotes: 1
Views: 774
Reputation: 222682
I think that you need a common table expression for this.
The idea is to do a cumulative sum that skips the rows that would cause the sum to go above 1000 (aliased sm
in the CTE), and to flag the records to skip (aliased keep
in the CTE). Then the outer query just filters on the flag.
with recursive cte as (
select
id,
amount,
case when amount > 1000 then 0 else amount end sm,
case when amount > 1000 then 0 else 1 end keep
from mytable
where id = 1
union all
select
t.id,
t.amount,
case when c.sm + t.amount > 1000 then c.sm else c.sm + t.amount end,
case when c.sm + t.amount > 1000 then 0 else 1 end
from cte c
inner join mytable t on t.id = c.id + 1
)
select id, amount from cte where keep = 1 order by id
id | amount -: | -----: 1 | 500 2 | 300 4 | 200
Upvotes: 1
Reputation: 1028
you should get the expected result using a recursively common table expression..
doing something like this..
with RECURSIVE yourtableOrdered as (select row_number() over (order by id) row_num, id, val from (values (1, 500), (2, 300), (3, 750), (4, 200), (5, 500)) V (id, val)),
lineSum as (
select row_num, id, val,
case when val <= 1000 then val else 0 end totalSum,
case when val <= 1000 then true else false end InResult
from yourtableOrdered
where row_num = 1
union all
select y.row_num, y.id, y.val,
case when previousLine.totalSum + y.val <= 1000 then previousLine.totalSum + y.val else previousLine.totalSum end totalSum,
case when previousLine.totalSum + y.val <= 1000 then true else false end InResult
from yourtableOrdered y
inner join lineSum previousLine
on y.row_num = previousLine.row_num + 1
),
yourExpectedResult as (
select * from lineSum where InResult = true
)
select * from yourExpectedResult
see a working sample in
http://sqlfiddle.com/#!17/2cbcf/1/0
Upvotes: 1
Reputation: 1271051
Use a cumulative sum:
select t.*
from (select t.*,
sum(amount) over (order by id) as running_amount
from t
) t
where running_amount - amount < 1000;
Upvotes: 0