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

前端 未结 2 528
暖寄归人
暖寄归人 2021-01-29 16:30

I have a table of driver speeds and road segments:

driver_lpr    |   segment    |    speed
  0000001     |       A      |     30
  0000002     |       B      |           


        
相关标签:
2条回答
  • 2021-01-29 17:00

    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
    
    0 讨论(0)
  • 2021-01-29 17:03

    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

    0 讨论(0)
提交回复
热议问题