How should I calculate the average speed by road segment for multiple segments?

不打扰是莪最后的温柔 提交于 2019-12-02 13:44:54
Uri Goren

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

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:

  • Addition of a 0 speed in segment B, will give average speed as 40 (60*2+0*1)/(2+1).
  • Addition of a new segment, 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:

  • There will be no change in average speed of B with addition of a 0.
  • However, a new segment 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!