Reputation: 1352
I have a table like this:
-----------+------------+-------
first | last | bytes
-----------+------------+-------
1441013602 | 1441013602 | 10
-----------+------------+-------
1441013602 | 1441013603 | 20
-----------+------------+-------
1441013603 | 1441013605 | 30
-----------+------------+-------
1441013610 | 1441013612 | 30
which
'first' column is switching time of the first packet of a traffic flow
'last' column is switching time of the last packet of a traffic flow
'bytes' is the volume of the traffic flow.
How can I calculate bandwidth usage for each second from 1441013602 to 1441013612 ?
I want this:
1441013602 20 B/s
1441013603 20 B/s
1441013604 10 B/s
1441013605 10 B/s
1441013606 0 B/s
1441013607 0 B/s
1441013608 0 B/s
1441013609 0 B/s
1441013610 10 B/s
1441013611 10 B/s
1441013612 10 B/s
Upvotes: 4
Views: 1690
Reputation: 51705
Here an approach at SQL Fiddle
PostgreSQL 9.3 Schema Setup:
create table t ( first int, last int, bytes int );
insert into t values
(1441013602 , 1441013602 , 10 ),
(1441013602 , 1441013603 , 20 ),
(1441013603 , 1441013605 , 30 ),
(1441013610 , 1441013612 , 30 );
The query:
with
bytes as
( select first, last,
( last - first ) as calc_time,
bytes
from t
where ( last - first )>0 ),
bytes_per_second as
( select first, last, bytes / calc_time as Bs
from bytes ),
calc_interval as
( SELECT * FROM generate_series(1441013602,1441013612) )
select
i.generate_series, bps.Bs
from
calc_interval i
left outer join
bytes_per_second bps
on i.generate_series between bps.first and bps.last - 1
order by
i.generate_series
| generate_series | bs |
|-----------------|--------|
| 1441013602 | 20 |
| 1441013603 | 15 |
| 1441013604 | 15 |
| 1441013605 | (null) |
| 1441013606 | (null) |
| 1441013607 | (null) |
| 1441013608 | (null) |
| 1441013609 | (null) |
| 1441013610 | 15 |
| 1441013611 | 15 |
| 1441013612 | (null) |
Explanation:
Upvotes: 2
Reputation: 324751
You can use PostgreSQL's generate_series
function for this. Generate a series of rows, one for each second, since that's what you want. Then left join on the table of info, so that you get one row for each second for each data flow. GROUP BY
seconds, and sum
the data flow bytes.
e.g:
SELECT seconds.second, coalesce(sum(t.bytes::float8 / (t.last::float8-t.first::float8+1)),0)
FROM generate_series(
(SELECT min(t1.first) FROM Table1 t1),
(SELECT max(t1.last) FROM Table1 t1)
) seconds(second)
LEFT JOIN table1 t
ON (seconds.second BETWEEN t.first and t.last)
GROUP BY seconds.second
ORDER BY seconds.second;
http://sqlfiddle.com/#!15/b3b07/7
Note that we calculate the bytes per second of the flow, then sum that over the seconds of the flow across all flows. This only gives an estimate, since we don't know if the flow rate was steady over the flow duration.
For formatting the bytes, use the format
function and/or pg_size_pretty
.
Upvotes: 3