我应该如何计算多个路段的平均速度?

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

我有 table 的 driver 速度和路段:

driver_lpr    |   segment    |    speed
  0000001     |       A      |     30
  0000002     |       B      |     60
  0000003     |       A      |     50
  0000004     |       A      |     100
  0000005     |       B      |     60

我希望每段的平均速度 table

segment   |   average speed
   A      |         47.368
   B      |         60

如何在 SQL 中完成?

平均速度时,需要harmonic mean

直截了当的AVG()方法是错误的,算术平均得出平均速度的错误结果。

调和平均值没有预定义函数,但可以通过以下查询实现:

SELECT segment,
       COUNT(*)/SUM(1e0/speed) AS avg_speed
FROM T 
GROUP BY segment

SQL Fiddle

这有点复杂,但也会照顾 0 速度。根据不同的场景,我有 2 个类似的查询。

假设您的来源 table 如下所示。

+-------------+----------+-------+
| 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 |
+-------------+----------+-------+

我以 0 的速度添加了 2 行。

案例一:

  • 在路段 B 中添加 0 速度,平均速度为 40 (60*2+0*1)/(2+1)
  • 添加新段,C0 速度将给出平均速度 0

所以输出将是

+----------+-------------------+
| segment  |   average_speed   |
+----------+-------------------+
| A        | 47.36842105263158 |
| B        | 40                |
| C        | 0                 |
+----------+-------------------+

SQLFiddle Demo CASE 1

案例二:

  • B 的平均速度不会因为增加一个 0
  • 但是,新路段 C 的平均速度为 0

输出将是

+----------+-------------------+
| segment  |   average_speed   |
+----------+-------------------+
| A        | 47.36842105263158 |
| B        | 60                |
| C        | 0                 |
+----------+-------------------+

SQLFiddle Demo CASE 2

案例 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

案例 2 的查询

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