寻找许多 Oracle 时间戳之间的平均值?
Finding average between many Oracle timestamps?
所以我正在尝试使用 Oracle 查找时间戳列表的平均值。我有一个为 itemX 增长的 table。每次调用 itemX 时,它都会将一个值压入我的 table。这可能是几天、几个月、几年的数据和时间戳。我所关心的只是最后 10 个时间戳的平均值,并且只有在最近 3 小时内。
我有这样的数据...
ROW_NUM itemX DEVICE_TIMESTAMP
1 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:46:51.000000 PM
2 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:45:50.000000 PM
3 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:44:49.000000 PM
4 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:43:49.000000 PM
5 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:42:49.000000 PM
6 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:41:48.000000 PM
7 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:40:47.000000 PM
8 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:39:46.000000 PM
9 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:38:45.000000 PM
10 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:37:44.000000 PM
使用:
select row_number() over(order by device_timestamp desc) row_num,
itemX, device_timestamp
from tracks_report
where device_timestamp >= sys_extract_utc(systimestamp) - INTERVAL '03:00' HOUR TO MINUTE
and itemX = '9094E4E56CAEF8D7E0531965000A285C'
order by device_timestamp desc
FETCH NEXT 10 ROWS ONLY
我想要得到的是这 10 行之间的平均时间。我尝试将其分解为秒和分钟,将它们相加除以 10,然后取平均值。但我的价值观不正确。这将是一个函数,我可以在其中根据 itemX id 调用它。
有什么建议吗?我应该得到大约 60 秒的时间。但结果是我的故障平均只有 47 秒左右。
您可以使用LAG
/LEAD
解析函数求出previous/next值,然后减去一个区间并提取组成部分和平均值:
SELECT itemx,
AVG(
EXTRACT( HOUR FROM diff_since_last ) * 3600
+ EXTRACT( MINUTE FROM diff_since_last ) * 60
+ EXTRACT( SECOND FROM diff_since_last )
) AS average_seconds_difference
FROM (
SELECT ROW_NUMBER() OVER ( PARTITION BY itemx ORDER BY device_timestamp DESC )
AS rn,
itemx,
device_timestamp,
device_timestamp
- LEAD( device_timestamp )
OVER ( PARTITION BY itemx ORDER BY device_timestamp DESC )
AS diff_since_last
FROM tracks_report t
) t
WHERE rn <= 10
AND FROM_TZ( device_timestamp, 'UTC' ) >= SYSTIMESTAMP - INTERVAL '3' HOUR
GROUP BY itemx
为测试数据:
CREATE TABLE tracks_report ( itemX, DEVICE_TIMESTAMP ) AS
SELECT 'A1',
CAST( TRUNC( SYSTIMESTAMP, 'HH' ) AS TIMESTAMP )
+ INTERVAL '1:01.000001' MINUTE TO SECOND * ( LEVEL - 1 )
FROM DUAL
CONNECT BY LEVEL <= 20
这输出:
ITEMX | AVERAGE_SECONDS_DIFFERENCE
:---- | -------------------------:
A1 | 61.000001
(注意:平均值包括小数秒,我认为这很重要,因为您使用的是 TIMESTAMP
数据类型而不是 DATE
数据类型。)
(注2:这是从最近的10个时间戳到前面的时间戳的平均间隔;所以它会考虑从第10个到第11个最近的时间戳的间隔,即使第11个时间戳是在 3 小时范围外,第 10 个在 3 小时内。如果您只想考虑所有值在 3 小时范围内的时间,则将过滤器从外部查询移动到内部查询。如果您想比较10 个值之间的 9 个间隔 [而不是 11 个值之间的 10 个间隔] 然后更改为 rn <= 9
。)
db<>fiddle here
与@MTO 的基本思想相同,但这使用您的原始查询 - 包括 filter/limit - 在 CTE 中:
with cte1 (row_num, itemx, device_timestamp) as (
select row_number() over(order by device_timestamp desc),
itemX,
device_timestamp
from tracks_report
where device_timestamp >= sys_extract_utc(systimestamp) - INTERVAL '03:00' HOUR TO MINUTE
and itemX = '9094E4E56CAEF8D7E0531965000A285C'
order by device_timestamp desc
FETCH NEXT 10 ROWS ONLY
)
select row_num,
itemX,
device_timestamp,
device_timestamp
- lead(device_timestamp) over (partition by itemX order by device_timestamp desc)
as diff_interval
from cte1;
然后您可以使用 extract()
:
从以秒为单位的间隔中得到差异
with cte1 (row_num, itemx, device_timestamp) as (
...
),
cte2 (row_num, itemX, device_timestamp, diff_interval) as (
select row_num,
itemX,
device_timestamp,
device_timestamp
- lead(device_timestamp) over (partition by itemX order by device_timestamp desc)
as diff_interval
from cte1
)
select row_num, itemX, device_timestamp, diff_interval,
extract(hour from diff_interval) * 3600
+ extract(minute from diff_interval) * 60
+ extract(second from diff_interval) as diff_seconds
from cte2;
而不是全部显示,取平均值:
with cte1 (row_num, itemx, device_timestamp) as (
...
),
cte2 (row_num, itemX, device_timestamp, diff_interval) as (
...
)
select avg(
extract(hour from diff_interval) * 3600
+ extract(minute from diff_interval) * 60
+ extract(second from diff_interval)
) as avg_diff_seconds
from cte2;
AVG_DIFF_SECONDS
----------------
60.7777778
我仍然发布这个的唯一原因是它的行为因应用 filter/limit 的位置而不同。这是查看最近 10 个时间戳之间的 9 个间隔的平均值(如果过去 3 小时内有那么多时间戳)。如果你在末尾应用 filter/limit 那么它将包括 10 号和 11 号之间的间隔,即使 11 号早很多小时也是如此。
当然是看你自己了,从问题上看还不是很清楚。
所以我正在尝试使用 Oracle 查找时间戳列表的平均值。我有一个为 itemX 增长的 table。每次调用 itemX 时,它都会将一个值压入我的 table。这可能是几天、几个月、几年的数据和时间戳。我所关心的只是最后 10 个时间戳的平均值,并且只有在最近 3 小时内。
我有这样的数据...
ROW_NUM itemX DEVICE_TIMESTAMP
1 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:46:51.000000 PM
2 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:45:50.000000 PM
3 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:44:49.000000 PM
4 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:43:49.000000 PM
5 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:42:49.000000 PM
6 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:41:48.000000 PM
7 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:40:47.000000 PM
8 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:39:46.000000 PM
9 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:38:45.000000 PM
10 9094E4E56CAEF8D7E0531965000A285C 3/23/2020 12:37:44.000000 PM
使用:
select row_number() over(order by device_timestamp desc) row_num,
itemX, device_timestamp
from tracks_report
where device_timestamp >= sys_extract_utc(systimestamp) - INTERVAL '03:00' HOUR TO MINUTE
and itemX = '9094E4E56CAEF8D7E0531965000A285C'
order by device_timestamp desc
FETCH NEXT 10 ROWS ONLY
我想要得到的是这 10 行之间的平均时间。我尝试将其分解为秒和分钟,将它们相加除以 10,然后取平均值。但我的价值观不正确。这将是一个函数,我可以在其中根据 itemX id 调用它。
有什么建议吗?我应该得到大约 60 秒的时间。但结果是我的故障平均只有 47 秒左右。
您可以使用LAG
/LEAD
解析函数求出previous/next值,然后减去一个区间并提取组成部分和平均值:
SELECT itemx,
AVG(
EXTRACT( HOUR FROM diff_since_last ) * 3600
+ EXTRACT( MINUTE FROM diff_since_last ) * 60
+ EXTRACT( SECOND FROM diff_since_last )
) AS average_seconds_difference
FROM (
SELECT ROW_NUMBER() OVER ( PARTITION BY itemx ORDER BY device_timestamp DESC )
AS rn,
itemx,
device_timestamp,
device_timestamp
- LEAD( device_timestamp )
OVER ( PARTITION BY itemx ORDER BY device_timestamp DESC )
AS diff_since_last
FROM tracks_report t
) t
WHERE rn <= 10
AND FROM_TZ( device_timestamp, 'UTC' ) >= SYSTIMESTAMP - INTERVAL '3' HOUR
GROUP BY itemx
为测试数据:
CREATE TABLE tracks_report ( itemX, DEVICE_TIMESTAMP ) AS
SELECT 'A1',
CAST( TRUNC( SYSTIMESTAMP, 'HH' ) AS TIMESTAMP )
+ INTERVAL '1:01.000001' MINUTE TO SECOND * ( LEVEL - 1 )
FROM DUAL
CONNECT BY LEVEL <= 20
这输出:
ITEMX | AVERAGE_SECONDS_DIFFERENCE :---- | -------------------------: A1 | 61.000001
(注意:平均值包括小数秒,我认为这很重要,因为您使用的是 TIMESTAMP
数据类型而不是 DATE
数据类型。)
(注2:这是从最近的10个时间戳到前面的时间戳的平均间隔;所以它会考虑从第10个到第11个最近的时间戳的间隔,即使第11个时间戳是在 3 小时范围外,第 10 个在 3 小时内。如果您只想考虑所有值在 3 小时范围内的时间,则将过滤器从外部查询移动到内部查询。如果您想比较10 个值之间的 9 个间隔 [而不是 11 个值之间的 10 个间隔] 然后更改为 rn <= 9
。)
db<>fiddle here
与@MTO 的基本思想相同,但这使用您的原始查询 - 包括 filter/limit - 在 CTE 中:
with cte1 (row_num, itemx, device_timestamp) as (
select row_number() over(order by device_timestamp desc),
itemX,
device_timestamp
from tracks_report
where device_timestamp >= sys_extract_utc(systimestamp) - INTERVAL '03:00' HOUR TO MINUTE
and itemX = '9094E4E56CAEF8D7E0531965000A285C'
order by device_timestamp desc
FETCH NEXT 10 ROWS ONLY
)
select row_num,
itemX,
device_timestamp,
device_timestamp
- lead(device_timestamp) over (partition by itemX order by device_timestamp desc)
as diff_interval
from cte1;
然后您可以使用 extract()
:
with cte1 (row_num, itemx, device_timestamp) as (
...
),
cte2 (row_num, itemX, device_timestamp, diff_interval) as (
select row_num,
itemX,
device_timestamp,
device_timestamp
- lead(device_timestamp) over (partition by itemX order by device_timestamp desc)
as diff_interval
from cte1
)
select row_num, itemX, device_timestamp, diff_interval,
extract(hour from diff_interval) * 3600
+ extract(minute from diff_interval) * 60
+ extract(second from diff_interval) as diff_seconds
from cte2;
而不是全部显示,取平均值:
with cte1 (row_num, itemx, device_timestamp) as (
...
),
cte2 (row_num, itemX, device_timestamp, diff_interval) as (
...
)
select avg(
extract(hour from diff_interval) * 3600
+ extract(minute from diff_interval) * 60
+ extract(second from diff_interval)
) as avg_diff_seconds
from cte2;
AVG_DIFF_SECONDS
----------------
60.7777778
我仍然发布这个的唯一原因是它的行为因应用 filter/limit 的位置而不同。这是查看最近 10 个时间戳之间的 9 个间隔的平均值(如果过去 3 小时内有那么多时间戳)。如果你在末尾应用 filter/limit 那么它将包括 10 号和 11 号之间的间隔,即使 11 号早很多小时也是如此。
当然是看你自己了,从问题上看还不是很清楚。