我应该如何计算多个路段的平均速度?
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
这有点复杂,但也会照顾 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)
。
- 添加新段,
C
和 0
速度将给出平均速度 0
所以输出将是
+----------+-------------------+
| segment | average_speed |
+----------+-------------------+
| A | 47.36842105263158 |
| B | 40 |
| C | 0 |
+----------+-------------------+
案例二:
B
的平均速度不会因为增加一个
0
。
- 但是,新路段
C
的平均速度为 0
。
输出将是
+----------+-------------------+
| segment | average_speed |
+----------+-------------------+
| A | 47.36842105263158 |
| B | 60 |
| C | 0 |
+----------+-------------------+
案例 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
我有 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
这有点复杂,但也会照顾 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)
。 - 添加新段,
C
和0
速度将给出平均速度0
所以输出将是
+----------+-------------------+
| segment | average_speed |
+----------+-------------------+
| A | 47.36842105263158 |
| B | 40 |
| C | 0 |
+----------+-------------------+
案例二:
B
的平均速度不会因为增加一个0
。- 但是,新路段
C
的平均速度为0
。
输出将是
+----------+-------------------+
| segment | average_speed |
+----------+-------------------+
| A | 47.36842105263158 |
| B | 60 |
| C | 0 |
+----------+-------------------+
案例 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