计算最后 10 条记录的平均值(值)postgresql
calculate avg(value) for last 10 records postgresql
我有一个棘手的任务,
假设我们有 table 个“Racings”,并且我们有 TRACK、CAR、CIRCLE_TIME 列
这是一个数据的示例:
id
track
car
circle_time
10
1
10
15
9
1
10
14
8
1
10
16
7
1
10
15
6
1
10
13
5
2
10
7
4
2
10
4
3
2
10
5
2
3
10
8
1
3
10
10
我需要的是,我再添加一个像 avg3_circle_time 这样的列,它会显示每首曲目的最后 3 circle_time 的平均时间,例如:
id
track
car
circle_time
avg3_circle_time
10
1
10
15
15
9
1
10
14
15
8
1
10
16
14.6
7
1
10
15
null
6
1
10
13
null
5
2
10
7
5.3
4
2
10
4
null
3
2
10
5
null
2
3
10
8
null
1
3
10
10
null
我知道它在 oracle 中是如何工作的,你可以使用像 rowid 这样的东西,但如果是 postgresql 我不知道,我有一个像 .....avg(circle_time) 这样的草稿OVER(PARTITION BY track,car.......) as avg3_circle_time..... 请帮我解决这个任务
您可以使用window函数来计算移动平均线:
SELECT track, id, car, circle_time, AVG(circle_time) OVER (
PARTITION BY track
ORDER BY id
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
)
FROM t
ORDER BY track, id
根据您对前三个的定义,window 可能是 ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
。
如果您只需要至少有 3 个圆圈可用的值
select *
, case when lag(id, 2) over(partition by TRACK, CAR order by id) is not null then
avg(CIRCLE_TIME) over(partition by TRACK, CAR order by id rows between 2 preceding and current row) end a
from Racing
order by id desc;
输出
id track car circle_time a
10 1 10 15 15.0000000000000000
9 1 10 14 15.0000000000000000
8 1 10 16 14.6666666666666667
7 1 10 15 null
6 1 10 13 null
5 2 10 7 5.3333333333333333
4 2 10 4 null
3 2 10 5 null
2 3 10 8 null
1 3 10 10 null
使用 LAED() 然后检查接下来的两行之一是否为 NULL。然后计算平均值的三个值的总和。
-- PostgreSQL
SELECT *
, CASE WHEN next_circle_time IS NULL OR next_next_circle_time IS NULL
THEN NULL
ELSE ((t.circle_time + COALESCE(next_circle_time, 0) + COALESCE(next_next_circle_time, 0)) / 3 :: DECIMAL) :: DECIMAL(10, 1)
END avg_circle_time
FROM (SELECT *
, LEAD(circle_time, 1) OVER (PARTITION BY track ORDER BY id DESC) next_circle_time
, LEAD(circle_time, 2) OVER (PARTITION BY track ORDER BY id DESC) next_next_circle_time
FROM Racings) t
另一种方法使用 AVG()
SELECT *
, CASE WHEN LEAD(circle_time, 2) OVER (PARTITION BY track ORDER BY id DESC) IS NULL
OR LEAD(circle_time, 1) OVER (PARTITION BY track ORDER BY id DESC) IS NULL
THEN NULL
ELSE AVG(circle_time) OVER (PARTITION BY track ORDER BY id DESC ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING)
END :: DECIMAL(10, 2) avg_circle_time
FROM Racings
请从 url 检查 两个查询 是否存在 https://dbfiddle.uk/?rdbms=postgres_11&fiddle=f0cd868623725a1b92bf988cfb2deba3
几个已发布的答案最终重复了 window 定义。您可以使用 window
子句避免这种情况:
select *,
case when row_number() over(track_window) > 2
then trunc(avg(CIRCLE_TIME) over(track_window rows 2 preceding), 1)
end a
from Racing
window track_window as (partition by track order by id)
order by id desc
请注意,在此示例中,track_window
是如何定义一次,然后为 row_number
和 avg
重新使用的。在后一种情况下,window 子句也用框架修饰 (rows 2 preceding
)。
我有一个棘手的任务, 假设我们有 table 个“Racings”,并且我们有 TRACK、CAR、CIRCLE_TIME 列 这是一个数据的示例:
id | track | car | circle_time |
---|---|---|---|
10 | 1 | 10 | 15 |
9 | 1 | 10 | 14 |
8 | 1 | 10 | 16 |
7 | 1 | 10 | 15 |
6 | 1 | 10 | 13 |
5 | 2 | 10 | 7 |
4 | 2 | 10 | 4 |
3 | 2 | 10 | 5 |
2 | 3 | 10 | 8 |
1 | 3 | 10 | 10 |
我需要的是,我再添加一个像 avg3_circle_time 这样的列,它会显示每首曲目的最后 3 circle_time 的平均时间,例如:
id | track | car | circle_time | avg3_circle_time |
---|---|---|---|---|
10 | 1 | 10 | 15 | 15 |
9 | 1 | 10 | 14 | 15 |
8 | 1 | 10 | 16 | 14.6 |
7 | 1 | 10 | 15 | null |
6 | 1 | 10 | 13 | null |
5 | 2 | 10 | 7 | 5.3 |
4 | 2 | 10 | 4 | null |
3 | 2 | 10 | 5 | null |
2 | 3 | 10 | 8 | null |
1 | 3 | 10 | 10 | null |
我知道它在 oracle 中是如何工作的,你可以使用像 rowid 这样的东西,但如果是 postgresql 我不知道,我有一个像 .....avg(circle_time) 这样的草稿OVER(PARTITION BY track,car.......) as avg3_circle_time..... 请帮我解决这个任务
您可以使用window函数来计算移动平均线:
SELECT track, id, car, circle_time, AVG(circle_time) OVER (
PARTITION BY track
ORDER BY id
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
)
FROM t
ORDER BY track, id
根据您对前三个的定义,window 可能是 ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
。
如果您只需要至少有 3 个圆圈可用的值
select *
, case when lag(id, 2) over(partition by TRACK, CAR order by id) is not null then
avg(CIRCLE_TIME) over(partition by TRACK, CAR order by id rows between 2 preceding and current row) end a
from Racing
order by id desc;
输出
id track car circle_time a
10 1 10 15 15.0000000000000000
9 1 10 14 15.0000000000000000
8 1 10 16 14.6666666666666667
7 1 10 15 null
6 1 10 13 null
5 2 10 7 5.3333333333333333
4 2 10 4 null
3 2 10 5 null
2 3 10 8 null
1 3 10 10 null
使用 LAED() 然后检查接下来的两行之一是否为 NULL。然后计算平均值的三个值的总和。
-- PostgreSQL
SELECT *
, CASE WHEN next_circle_time IS NULL OR next_next_circle_time IS NULL
THEN NULL
ELSE ((t.circle_time + COALESCE(next_circle_time, 0) + COALESCE(next_next_circle_time, 0)) / 3 :: DECIMAL) :: DECIMAL(10, 1)
END avg_circle_time
FROM (SELECT *
, LEAD(circle_time, 1) OVER (PARTITION BY track ORDER BY id DESC) next_circle_time
, LEAD(circle_time, 2) OVER (PARTITION BY track ORDER BY id DESC) next_next_circle_time
FROM Racings) t
另一种方法使用 AVG()
SELECT *
, CASE WHEN LEAD(circle_time, 2) OVER (PARTITION BY track ORDER BY id DESC) IS NULL
OR LEAD(circle_time, 1) OVER (PARTITION BY track ORDER BY id DESC) IS NULL
THEN NULL
ELSE AVG(circle_time) OVER (PARTITION BY track ORDER BY id DESC ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING)
END :: DECIMAL(10, 2) avg_circle_time
FROM Racings
请从 url 检查 两个查询 是否存在 https://dbfiddle.uk/?rdbms=postgres_11&fiddle=f0cd868623725a1b92bf988cfb2deba3
几个已发布的答案最终重复了 window 定义。您可以使用 window
子句避免这种情况:
select *,
case when row_number() over(track_window) > 2
then trunc(avg(CIRCLE_TIME) over(track_window rows 2 preceding), 1)
end a
from Racing
window track_window as (partition by track order by id)
order by id desc
请注意,在此示例中,track_window
是如何定义一次,然后为 row_number
和 avg
重新使用的。在后一种情况下,window 子句也用框架修饰 (rows 2 preceding
)。