Oracle中按照时间范围以及时间间隔抽取数据的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle中按照时间范围以及时间间隔抽取数据的问题相关的知识,希望对你有一定的参考价值。

1.有一张表,里面有三个字段 ID-标示,Value-值,CreateTime
2.每次向表中存入17条CreateTime一样但是Value值不一样的数据,大概存了1000W条左右
3.目前需要一个查询语句 以时间范围和时间间隔为查询标准 取出满足条件的数据,例如:
查询时间范围为2012年10月1日 1:00 - 2012年10月1日 12:00数据中间隔时间是60秒 的所有数据! 这样查询的SQL语句应该如何写? Tks!

SELECT * FROM 表名 A
where a.CreateTime between to_date('2012-10-01 01:00:00','YYYY-MM-DD HH24:MI:SS')
and to_date('2012-10-01 12:00:00','YYYY-MM-DD HH24:MI:SS')
and to_char(CreateTime,'SS') = '00'
-- 秒位上数据为'00'的,这样非00秒比如05,10等其它的就过滤掉了
其它条件根据需要再加追问

and to_char(CreateTime,'SS') = '00'

这个是秒位数上的 那么,怎么根据这个来求得间隔时间 进行数据抽样.. 不懂..能具体一点么!
关键是间隔时间的条件 整不来.

追答

你可以看下我标准的字符串转日期函数
字符串转日期:to_date('2012-10-01 01:00:00','YYYY-MM-DD HH24:MI:SS')
日期转字符串:to_char(sysdate,‘YYYY-MM-DD HH24:MI:SS')
SS表示秒, to_char(sysdate,'SS')得到当前的秒
像你需求里的,正好60秒一个周期, 那你限制to_char(CreateTime,'SS')='00'
就可以实现需求了,如果要半分钟一个周期,可以试试mod(to_number(to_char(CreateTime,'SS')),30)=0,mod是得除后余数的函数

追问

现在按这样来试的话就相当于只对单条数据进行限制,这样会漏掉很多结果,应为在存入数据的时候,CreateTime 的秒上并不会是 00,是60秒内的任意一个数.
假设我存入了20次数据 每次17条那么
1: CreateTime: 2012年10月1日 1:00:02 17条记录
2: CreateTime: 2012年10月1日 1:01:02
...
20 -----CreateTime: 2012年10月1日 1:25:25
按照取的话就没有根据上组记录的时间和下一组记录的时间进行对比.

追答

目测你说的可能是个监控采样的数据
制定的规则是60秒为周期,所以那么写是没有问题的
先可以观察一下数据,最后一位秒上大多数为什么(比如02也好00也好),然后在你的查询中使用该限制
如果你说,有的是00秒,有的是02秒,那规则就没法定了,如果怕因为采集有时间误差
你可以试试最后的条件改为
and ( to_char(CreateTime,'SS') = '00'
or to_char(CreateTime,'SS') = '01'
or to_char(CreateTime,'SS') = '59')
这样秒的位数为59~00~01都可以留下来,但理论上就可能存在冗余数据

追问

就是设备传输上来的数据,所以存入的时间是不一致的 CreateTime 的秒可能是0-59内的任意数字,所以需要对数据做一个处理:
根据存入的数据-上一组数据-这一组数据-下一组数据 的时间进行计算。
如果说差值时间 在允许的间隔时间范围内(比如说60秒内或者是8秒内)就取出,如果不满足就丢弃.
如果用程序写,只能在一个可控的时间范围内进行查询排序以及过滤.加上是网络传输那就慢得不行了,所以需要写一个SQL处理

追答

1. 如果没有其它间隔规则(比如10秒一个、5秒一个)干扰
我之前的写法就ok
2. 如果你拿不准数据的分布(比如秒的位数都是1x还是2x),可以先用下面的sql统计下秒位上的数值分布情况
SELECT to_char(CreateTime,'YYYY-MM-DD HH24:MI') GRP_MIN--以每分钟为单元分组,如果要以小时,把格式中最后的:MI去掉
,AVG(to_number(to_char(CreateTime,'SS'))) avg_sec -- 平均秒位上的值
,COUNT(*) nums -- 分组的采样数量
FROM 表名 A
where a.CreateTime between to_date('2012-10-01 01:00:00','YYYY-MM-DD HH24:MI:SS')
and to_date('2012-10-01 12:00:00','YYYY-MM-DD HH24:MI:SS')
and to_char(CreateTime,'SS') = '00'
GROUP BY to_char(CreateTime,'YYYY-MM-DD HH24')

参考技术A 我这样理解:时间段内“整分”数据,也即秒为0的数据(CreateTime 为varchar2或date时分别如下)

select a.CreateTime
from 表 a
where extract(second from to_timestamp(a.CreateTime, 'yyyy-mm-dd hh24:mi:ss'))=0
and a.CreateTime >='2012-10-01 01:00:00' and a.CreateTime <='2012-10-01 12:00:00'

select a.CreateTime
from 表 a
where extract(second from to_timestamp(to_char(a.CreateTime,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'))=0
and a.CreateTime between to_date('2012-10-01 1','yyyy-mm-dd hh24:mi:ss') and to_date('2012-10-01 12','yyyy-mm-dd hh24:mi:ss')
参考技术B 这里TT是指定的时间间隔,单位:秒 下面语句可查出任意给定时间间隔的所有记录。
select * from tab
where CreateTime between to_date('2012-10-01 01:00:00','yyyy-mm-dd hh24:mi:ss') and
to_date('2012-10-01 12:00:00','yyyy-mm-dd hh24:mi:ss') and
CreateTime in (select to_date('2012-10-01 01:00:00','yyyy-mm-dd hh24:mi:ss')
+TT*rownum/24/60/60 from dual
CONNECT BY rownum<=
(to_date('2012-10-01 12:00:00','yyyy-mm-dd hh24:mi:ss')-
to_date('2012-10-01 01:00:00','yyyy-mm-dd hh24:mi:ss'))*24*60*60/TT);
在上面的语句中,下列部分是构造时间间隔的所有可能存在的记录。每TT秒一条记录。
(select to_date('2012-10-01 01:00:00','yyyy-mm-dd hh24:mi:ss') +TT*rownum/24/60/60
from dual CONNECT BY rownum<=
(to_date('2012-10-01 12:00:00','yyyy-mm-dd hh24:mi:ss')-
to_date('2012-10-01 01:00:00','yyyy-mm-dd hh24:mi:ss'))*24*60*60/TT)
不知道我理解的对不对,仅供参考。

按日期间隔分组 Oracle

【中文标题】按日期间隔分组 Oracle【英文标题】:Group by date intervall Oracle 【发布时间】:2021-02-25 06:18:33 【问题描述】:

我想从一个表中检索整个月的重量数据总和。 我需要帮助的是我想将结果分为两部分 每月 1-15 的总和 以及当月的第二行 16-31。

SELECT(SUM(B.SCALE_WEIGHT) FROM TRACKING.DATALOG_TAB B WHERE B.MATERIALID= 1 AND B.SCALE_EVENTDATE BETWEEN TO_DATE(TRUNC(TO_DATE('2020-10-1', 'YYYY-MM-DD'),'MONTH')) AND TO_DATE(TRUNC(TO_DATE('2020-10-1', 'YYYY-MM-DD'), 'MONTH')+30)
GROUP BY(somthing like this - 1-15  and 16-31)

【问题讨论】:

【参考方案1】:

这是一种选择:

select
    1 + floor(extract(day from scale_eventdate) / 16) as fortnight,
    sum(b.scale_weight) as sum_scale_weight
from tracking.datalog_tab b 
where 
    materialid = 1 
    and scale_eventdate >= date '2020-10-01'
    and scale_eventdate <  date '2020-11-01'
group by 1 + floor(extract(day from scale_eventdate) / 16)

这会从日期中提取天数,然后使用算法:从该月的 1 日到 15 日的每一天都转到fortnight 编号1,之后的所有内容都转到存储桶2

我们也可以使用 to_char()case 表达式来做到这一点,这在某种程度上更具表现力:

select
    case when to_char(scale_eventdate, 'dd') <= '15' then 1 else 2 end as fortnight,
    sum(b.scale_weight) as sum_scale_weight
from tracking.datalog_tab b 
where 
    materialid = 1 
    and scale_eventdate >= date '2020-10-01'
    and scale_eventdate <  date '2020-11-01'
group by case when to_char(scale_eventdate, 'dd') <= '15' then 1 else 2 end

请注意,我将日期过滤逻辑更改为使用标准日期文字,这使得查询更短且更具可读性。

【讨论】:

那是正确的,但我想选择多列?另一列 fo materialId = 2 @B.j:这确实是一个不同的问题。如果是这样,您应该提出一个新问题。这回答了您提出的问题。 发了一个新的***.com/questions/64820490/…

以上是关于Oracle中按照时间范围以及时间间隔抽取数据的问题的主要内容,如果未能解决你的问题,请参考以下文章

Oracle中的时间间隔型数据掌握方法

Oracle中根据时间范围查询数据

要求:oracle数据库,按照时间间隔2分钟查询数据,结果如第一行数据是13:55的数据,第二条就是13:57的

oracle 11g中怎么将查询指定的数据不在指定的字段方法

pandas使用date_range函数以及datetime函数创建从当前时间为起始时间间隔为天的指定长度时间范围(periods)的时间序列数据设置normalize参数只保留日期信息

Oracle整合Mybatis实现list数据插入时,存在就更新,不存在就插入以及随机抽取一条记录