How can I select just some rows in the following table so that they sum up to certain value?
Table
-----
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
2 | 1.5 | 0.0 | 7.5 | 18
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
Let's say, the top value I want is 57...
So I need to select the rows from the previous table such that qty1+qty2+qty3+qty4 of each row, get until that 57 value, and discard the other rows. In this example, I would get the following:
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
2 | 1.5 | 0.0 | 7.5 | 18
Because 10+20+1.5+7.5+18 = 57, so I discard rows 3 & 4...
Now I wish that the top value is 50, then I should get:
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
2 | 1.5 | 0.0 | 7.5 | 11
Since these values sum up to 50, and the 7 from row2,qty4 is left out... (BTW the rows are ordered in this particular way because that's the order in which I wish to account for the sums of qtys... It's not valid to sum up first row1, then 3, then 2 then 4, for example... They should always be sumed in the order 1,2,3,4...)
What if I would like the complement of this? I mean, the other two rows I didn't got in the last result.
First case:
id | qty1 | qty2 | qty3 | qty4
------------------------------
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
Second case:
id | qty1 | qty2 | qty3 | qty4
------------------------------
2 | 0.0 | 0.0 | 0.0 | 7
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
(If the second case is too complicated, how about obtaining:
id | qty1 | qty2 | qty3 | qty4
------------------------------
1 | 0.0 | 0.0 | 10 | 20
Because adding up the original qtys of row 2 would surpass the 50 value, I discard it... The complement in this case should just be:
id | qty1 | qty2 | qty3 | qty4
------------------------------
2 | 1.5 | 0.0 | 7.5 | 18
3 | 1.0 | 2.0 | 7.5 | 18
4 | 0.0 | 0.5 | 5 | 13
)
Let's put it this way: If SQL was a religion I'd go to hell for providing this solution. SQL is not meant to solve this kind of problems, so any solution would be horrible. Mine is no exception :)
set @limitValue := 50;
select id, newQty1, newQty2, newQty3, newQty4 from (
select id,
if(@limitValue - qty1 > 0, qty1, greatest(@limitValue, 0)) newQty1,
@limitValue := @limitValue - qty1 Total1,
if(@limitValue - qty2 > 0, qty2, greatest(@limitValue, 0)) newQty2,
@limitValue := @limitValue - qty2 Total2,
if(@limitValue - qty3 > 0, qty3, greatest(@limitValue, 0)) newQty3,
@limitValue := @limitValue - qty3 Total3,
if(@limitValue - qty4 > 0, qty4, greatest(@limitValue, 0)) newQty4,
@limitValue := @limitValue - qty4 Total4
from (
select id, qty1, qty2, qty3, qty4,
@rowTotal < @limitValue Useful,
@previousRowTotal := @rowTotal PreviousRowTotal,
@rowTotal := @rowTotal + qty1 + qty2 + qty3 + qty4 AllRowsTotal,
@rowTotal - @previousRowTotal CurrentRowTotal
from t,
(select @rowTotal := 0, @previousRowTotal := 0) S1
) MarkedUseful
where useful = 1
) Final
For the provided data, this results in:
+----+---------+---------+---------+---------+
| ID | NEWQTY1 | NEWQTY2 | NEWQTY3 | NEWQTY4 |
+----+---------+---------+---------+---------+
| 1 | 0 | 0 | 10 | 20 |
| 2 | 1.5 | 0 | 7.5 | 11 |
+----+---------+---------+---------+---------+
And the complement:
set @limitValue := 50;
select t1.id,
coalesce(t1.qty1 - newQty1, t1.qty1) newQty1,
coalesce(t1.qty2 - newQty2, t1.qty2) newQty2,
coalesce(t1.qty3 - newQty3, t1.qty3) newQty3,
coalesce(t1.qty4 - newQty4, t1.qty4) newQty4
from t t1 left join (
select id,
if(@limitValue - qty1 > 0, qty1, greatest(@limitValue, 0)) newQty1,
@limitValue := @limitValue - qty1 Total1,
if(@limitValue - qty2 > 0, qty2, greatest(@limitValue, 0)) newQty2,
@limitValue := @limitValue - qty2 Total2,
if(@limitValue - qty3 > 0, qty3, greatest(@limitValue, 0)) newQty3,
@limitValue := @limitValue - qty3 Total3,
if(@limitValue - qty4 > 0, qty4, greatest(@limitValue, 0)) newQty4,
@limitValue := @limitValue - qty4 Total4
from (
select id, qty1, qty2, qty3, qty4,
@rowTotal < @limitValue Useful,
@previousRowTotal := @rowTotal PreviousRowTotal,
@rowTotal := @rowTotal + qty1 + qty2 + qty3 + qty4 AllRowsTotal,
@rowTotal - @previousRowTotal CurrentRowTotal
from t,
(select @rowTotal := 0, @previousRowTotal := 0) S1
) MarkedUseful
where useful = 1
) Final
on t1.id = final.id
where Total1 < 0 or Total2 < 0 or Total3 < 0 or Total4 < 0 or final.id is null
For the provided data, this results in:
+----+---------+---------+---------+---------+
| ID | NEWQTY1 | NEWQTY2 | NEWQTY3 | NEWQTY4 |
+----+---------+---------+---------+---------+
| 2 | 0 | 0 | 0 | 7 |
| 3 | 1 | 2 | 7.5 | 18 |
| 4 | 0 | 0.5 | 5 | 13 |
+----+---------+---------+---------+---------+
Enjoy!



