简体   繁体   中英

MySQL subtract two similar rows and multiply results by another row

I want to be able to subtract the qty of ondemand to reserved from the same zone, type and os and then multiply the remaining qty by the rate.

Here is a sample dump of the mysql data

| Zone  | Type  | Qty | OS    | Reservation | Rate  |
| zone1 | type1 | 12  | linux | ondemand    | 0.24  |
| zone1 | type1 | 6   | linux | reserved    | 0.056 |
| zone1 | type2 | 3   | linux | ondemand    | 0.82  |
| zone2 | type1 | 5   | mswin | ondemand    | 0.24  |
| zone2 | type1 | 2   | mswin | reserved    | 0.056 |
| zone2 | type2 | 3   | linux | ondemand    | 0.82  |
| zone3 | type1 | 4   | linux | ondemand    | 0.24  |
| zone3 | type1 | 1   | linux | reserved    | 0.056 |

The result would be

| Zone  | Type  | Qty | OS    | Reservation | Rate  | sum() |
| zone1 | type1 | 6   | linux | ondemand    | 0.24  | 1.44  |
| zone1 | type1 | 6   | linux | reserved    | 0.056 | 0.336 |
| zone1 | type2 | 3   | linux | ondemand    | 0.82  | 0.246 |
| zone2 | type1 | 3   | mswin | ondemand    | 0.24  | 0.72  |
| zone2 | type1 | 2   | mswin | reserved    | 0.056 | 0.112 |
| zone2 | type2 | 3   | linux | ondemand    | 0.82  | 0.246 |
| zone3 | type1 | 3   | linux | ondemand    | 0.24  | 0.72  |
| zone3 | type1 | 1   | linux | reserved    | 0.056 | 0.056 |

I am not sure how to get a distinct statement to work with this. I don't know if this is possible with mysql or if I would need to script it and then produce the output. Any help is appreciated.

There isn't always a corresponding reserved in the zone for a type and os that contains an ondemand.

You need to join the table to itself:

select
    t1.Zone, t1.Type, t1.Qty - ifnull(t2.Qty, 0), t1.OS,
    t1.rate, (t1.Qty - ifnull(t2.Qty, 0)) * t1.rate as total
from mytable t1
left join mytable t2
    on t1.zone = t2.zone
    and t1.type = t2.type
    and t1.os = t2.os
    and t2.reservation = 'reserved'

and t1.reservation = 'ondemand'

Ihe critical kung fu is the last condition in the join condition. It ensures there is only a join for the "ondemand" rows - with a left join , all other row types (and those "ondenand" rows without a corresponding "reserved" row) will get a null for there join qty value (hence the ifnull() to give them a zero to work with).

Note that this will correctly calculate the total even if there are no matching "reserved" rows for the "ondemand" rows.

To be honest, I've never seen this kind of query before where only some of the rows from the parent side are joined to, but all rows are kept.

This has not been run, but something like this maybe?

select zone, type, os, ondemand_cnt, reserved_cnt, ondemand_cnt-reserved_cnt as cnt, 
<some_rate>*(ondemand_cnt-reserved_cnt) as calc_rate
from
(
select zone, type, os, sum(qty) as ondemand_cnt 
from table
where reservation = 'ondemand'
group by zone, type, os
) as o
join
(
select zone, type, os, sum(qty) as reserved_cnt
from table
where reservation = 'reserved'
group by zone, type, os
) as r on (o.zone = r.zone and o.type = r.type and o.os = r.os)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM