Mysql – Add multiples of rows till they satisfy an arbitrary sum then return the rows that do

MySQL

Am not sure if this is possible. Let's say I have an arbitrary figure like 200, I have a table with two columns (both ints). Lets call the columns col_a and col_b.

I need to perform one query such that if col_a * col_b for the first row does not equal to my arbitrary figure (in this case 200), keep whatever value the first row equates to and go to second row, do the same while adding the results to the value we got from the first row, repeat this till the total equates to our arbitrary value.

In an example. Lets use our arbitrary figure of 200 say we have row 1 (col_a*colb) = 20, row 2 (col_a*col_b) = 70, row 3 (col_a*colb) = 110, row 4 (col_a*col_b) = 30.

My query should return row 1, row 2 and row 3. How is this possible in sql? I am using mysql.

Best Answer

You could use user defined variable in mysql to achieve your goal:

create table t ( id int not null auto_increment, 
                 col_a int not null, 
                 col_b int not null, 
                 primary key(id) );

insert into t(col_a, col_b) values (1,20), (1,70), (1,110), (1,30);

set @sum := 0;
select *, col_a * col_b, @sum as s 
from t
where (@sum := @sum + (col_a * col_b)) <= 200
order by id; 

+----+-------+-------+---------------+------+
| id | col_a | col_b | col_a * col_b | s    |
+----+-------+-------+---------------+------+
|  1 |     1 |    20 |            20 |   20 |
|  2 |     1 |    70 |            70 |   90 |
|  3 |     1 |   110 |           110 |  200 |
+----+-------+-------+---------------+------+
3 rows in set (0.00 sec)

You must use order by to make sure of the rows order as suggested by ypercube. For example you can sum column in reverse order.

set @sum := 0;
select *, col_a * col_b, @sum as s  
from t where (@sum := @sum + (col_a * col_b)) <= 200 
order by id desc;

+----+-------+-------+---------------+------+
| id | col_a | col_b | col_a * col_b | s    |
+----+-------+-------+---------------+------+
|  4 |     1 |    30 |            30 |   30 |
|  3 |     1 |   110 |           110 |  140 |
+----+-------+-------+---------------+------+
2 rows in set (0.00 sec)