I have a table of driver speeds and road segments:
driver_lpr | segment | speed
0000001 | A | 30
0000002 | B |
This is little bit complex, but will take care of 0
speed also. I have 2 similar queries to do it based on different scenarios.
Assume your source table like below.
+-------------+----------+-------+
| driver_lpr | segment | speed |
+-------------+----------+-------+
| 0000001 | A | 30 |
| 0000002 | B | 60 |
| 0000003 | A | 50 |
| 0000004 | A | 100 |
| 0000005 | B | 60 |
| 0000006 | B | 0 |
| 0000007 | C | 0 |
+-------------+----------+-------+
I have added 2 new rows with 0
speed.
Case 1:
0
speed in segment B
, will give average speed as
40
(60*2+0*1)/(2+1)
. C
with 0
speed will give average speed as 0
So output would be
+----------+-------------------+
| segment | average_speed |
+----------+-------------------+
| A | 47.36842105263158 |
| B | 40 |
| C | 0 |
+----------+-------------------+
SQLFiddle Demo CASE 1
Case 2:
B
with addition of a
0
. C
will have 0
average speed.Output would be
+----------+-------------------+
| segment | average_speed |
+----------+-------------------+
| A | 47.36842105263158 |
| B | 60 |
| C | 0 |
+----------+-------------------+
SQLFiddle Demo CASE 2
Query for Case 1:
with tbl1 as
(SELECT segment,
case when speed = 0 then cast(0 as float) else
cast(1 as float)/cast(speed as float)
end as newspeed
FROM T
),
tbl2 as
(
select segment,cast(1 as float)/avg(newspeed) as avgspeed,count(*) as cnt
from tbl1
where newspeed <> 0
group by segment
union
select segment,0 as avgspeed,count(*) as cnt
from tbl1
where newspeed =0
group by segment
)
select segment,
sum(avgspeed*cnt)/sum(cnt) as "average_speed"
from tbl2
group by segment
Query for Case2
with tbl1 as
(SELECT segment,
case when speed = 0 then cast(0 as float) else
cast(1 as float)/cast(speed as float)
end as newspeed
FROM T
),
tbl2 as
(
select segment,cast(1 as float)/avg(newspeed) as avgspeed,count(*) as cnt
from tbl1
where newspeed <> 0
group by segment
union
select segment,0 as avgspeed,count(*) as cnt
from tbl1
where newspeed =0
group by segment
)
select segment,
sum(avgspeed) as "average_speed"
from tbl2
group by segment
When averaging speeds, the harmonic mean is in need.
The straight forward AVG()
approach is wrong, the arithmetic mean yields the wrong result for average velocity.
There is no predefined function for the harmonic mean, but it could be achieved with this query:
SELECT segment,
COUNT(*)/SUM(1e0/speed) AS avg_speed
FROM T
GROUP BY segment
SQL Fiddle