一天当中不同时间段的累加

图片说明
有样一张表。
其中字段status有六种状态SYSOPEN、SYSCOLOE、WAIT 、WORK 、STOP、 ALAM
其中SYSCLOSE对应的时间减去SYSOPEN对应的时间的值为开机时间.SYSOPEN和SYSCLOSE 在一天中出现的次数不定。同日期的不同时段的SYSCLOSE和SYSOPEN相减的值之和,为一天内的开机总时间。

查询天数为任意日期范围(如2015.10.1---2015.10.31),求的查询日期范围内每天的开机总时间
求高手指点!!!

为什么没人什么回答啊,着急!!!,是我说的不够清楚吗?

这个你可以分开几步写,然后综合到一起:
先查询指定的日志范围;然后查同一个日期内的开机和关机时间;开机和关机是一对的,也就是说你开了机下一次就只能关机了,所以就没有必要判断下一次
是不是关机,如果现在是开机那下一次就肯定是关机;所以你判断当前状态如果为开机然后查一下关机在什么时候直接相减就可以了;然后用聚合函数sum一下,

不管你使用那种语言,系统的时间约定一天的值等于1。
你可通过打开该表数据,指定日期范围并设置排序为时间的反序,(时间晚的前),这样通过累加,close-open值,就是该日期内的累计值。

你可以将一天内所有关机时间总和求出来然后减去开机时间的总和;我没有测,你可以测测的

这个是最简单的;因为要求答十个字以上,所以填上点废话

SELECT SUM(tb.close_time-tb1.begin_time) AS open_time FROM (SELECT SUM(UNIX_TIMESTAMP(curtime)) AS close_time,DATE(curtime) AS day_date FROM table WHERE curtime BETWEEN '2015-10-01' AND '2015-10-02' AND status='SYSCLOSE' GROUP BY DATE(curtime)) tb LEFT JOIN (SELECT SUM(UNIX_TIMESTAMP(curtime)) AS begin_time,DATE(curtime) AS day_date FROM table WHERE curtime BETWEEN '2015-10-01' AND '2015-10-02' AND status='SYSOPEN' group by DATE(curtime)) tb1 ON tb.day_date = tb1.day_date;

这个是mysql 的写法,一天的关机时间和减去一天的开机时间和 等于一天总的开机时间

http://download.csdn.net/download/kunkun1014/6856309

楼上说的有道理,不过case不能覆盖完全,且不易规避,有一种情况会有问题,如求2015-10-02到2015-10-05期间的开机时间,2015-10-01开机,2015-10-02第一条数据是关机数据,同理2015-10-05最后是开机状态。这两种case没有涉及。
完全用sql实现我不太清楚。逻辑可以结合sql和代码实现:

1.使用sql:SELECT curTime, status FROM table WHERE status in ('SYSOPEN','SYSCOLOE') AND curTime BETWEEN '2015-10-01' AND '2015-10-05' ORDER BY curTime ASC; //其中 '2015-10-01'和'2015-10-05'是传入的期间参数
取出要求期间内的所有开机和关机时间升序排列。

2.代码中循环结果集,简单写:例如Entity为对应实体类
注:下面我把curTime当作已经转换为long,如何转换根据所用语言语法去做即可。

    使用sql获取结果集result。
    long sum = 0;
        int index = 0;
    if( 取result的第一条数据判断不是开机数据)
    {
            //case1,起始日期时已经是开机状态
        sum = curTime减去0点的差;
                index = 1;
    }

        long start = 0;

        for(index <result.count)
        {
            Entity entity = result[index];

                if(entity.status == SYSOPEN){
                    start = entity.curTime; 
                }else{
                    sum += entity.curTime - start;
                        start = 0;
                }
        }

        if(start != 0){
            // case2终止日期最后未关机。
            sum += 24点 - start; 
        }

sum即为总开机时间,转换成需要的格式即可。

sql语句查询是可以查询时间段。直接从昨天的0:0:0到23:59:59就是一天的时间段。

首先,我觉得方法不对,如果一个开机时间是23点,关机时间却是第二天的1点,那么按照上面所述的方法,计算出一天的开机时间是错误的。
如果能保证,没有跨越零点的开关机,则上面的算法就没问题了。

我认为,应该对该表做一定的修改,增加列,或者增加关联表。记录每条记录的开机时间。这样如果获取某一天的开机时间的,只需要获取改列的sum就可以了。
如果有跨越0点的开关机操作,则应对当天首先出现system close的记录和当天最后出现为system open的记录做特殊处理。

看你截图有自增字段,这里写个mysql的语句吧。
考虑到了开机和关机跨天的逻辑。如果跨天,则以只算当天的持续时间。
当然了,这里只统计一天的,如果统计多天的,变量设置start_date和end_date来写,类似。
tableName替换成表名,sql可直接执行。

set @date = STR_TO_DATE('2015-10-02','%Y-%m-%d %H:%i:%s');

select sum(unix_timestamp(t.closeTime) - unix_timestamp(t.openTime)) -- select timediff(t.closeTime, t.openTime)
from
(SELECT (select ifnull(max(curTime), @date) from tableName tb2 where tb2.id=@date) as 'openTime'
, curTime as 'closeTime'
FROM tableName tb1
where curTime >= @date and curTime < date_add(@date, INTERVAL 1 day)
and status = 'SYSCLOSE'
union
SELECT curTime as 'openTime'
, (select ifnull(min(curTime), date_add(@date, INTERVAL 1 day)) from tableName tb3 where tb3.id>tb1.id and status='SYSCLOSE' and curTime FROM tableName tb1
where curTime >= @date and curTime < date_add(@date, INTERVAL 1 day)
and status = 'SYSOPEN'
) t;

上面好像贴错了?,看这个吧:
set @date = STR_TO_DATE('2015-10-02','%Y-%m-%d %H:%i:%s');

select sum(unix_timestamp(t.closeTime) - unix_timestamp(t.openTime))
-- select t.closeTime, t.openTime, timediff(t.closeTime, t.openTime)
from
(SELECT (select ifnull(max(curTime), @date) from tableName tb2 where tb2.id=@date) as 'openTime'
, curTime as 'closeTime'
FROM tableName tb1
where curTime >= @date and curTime < date_add(@date, INTERVAL 1 day)
and status = 'SYSCLOSE'
union
SELECT curTime as 'openTime'
, (select ifnull(min(curTime), date_add(@date, INTERVAL 1 day)) from tableName tb3 where tb3.id>tb1.id and status='SYSCLOSE' and curTime FROM tableName tb1
where curTime >= @date and curTime < date_add(@date, INTERVAL 1 day)
and status = 'SYSOPEN'
) t;

好吧,原来把大于小于号当注释了额

好吧,原来把大于小于号当注释了

整体思路: 以当天的0点作为一个定点标尺,用 每天关机时间距离当天0点的时间总和 sum2 减去 每天开机时间距离当天0点的时间总和 sum1 就是当天开机时间sum3,如果最后一条为sysopen 说明当天没有关机 则相当于最后关机时间为24点,那么sum2再加上一天的时间即86400秒即可 即相当于sum3 +86400; 最后写个循环,遍历开始日期到结束日期所有的开机时间。如有不妥欢迎指点。望采纳。

============存储过程=====================
create or replace procedure DUANTIME_PRC(prm_startdate in varchar2,--开始日期
prm_enddate in varchar2,--结束日期
prm_time out varchar2,--返回秒 格式 2016-09-08:46800,2016-09-09:28800
prm_appcode out number) is
sum1 number;--当日开机时间距零点时间总和
sum2 number;--当日关机时间距零点时间总和
sum3 number;--当日开机时间总和
lastType varchar2(100);--最后一条记录
days number;--天数
tempstartDate varchar2(100);--临时日期,loop循环用
begin
sum1:=0;
sum2:=0;
sum3:=0;
prm_time:='';
select to_date(prm_enddate,'yyyy-mm-dd')-to_date(prm_startdate,'yyyy-mm-dd') into days from dual;
for i in 0 .. days loop
sum3:=0;
select to_char(to_date(prm_startdate,'yyyy-mm-dd')+i,'yyyy-mm-dd') into tempstartDate from dual;
select sum(ROUND(TO_NUMBER(DTimes - to_date(tempstartDate||' 00:00:00','yyyy-MM-dd HH24:mi:ss')) * 24 * 60 * 60)) into sum1 from DUANTIME t where to_char(dtimes, 'yyyy-MM-dd') = tempstartDate and dtype='SYSOPEN';
select sum(ROUND(TO_NUMBER(DTimes - to_date(tempstartDate||' 00:00:00','yyyy-MM-dd HH24:mi:ss')) * 24 * 60 * 60)) into sum2 from DUANTIME t where to_char(dtimes, 'yyyy-MM-dd') = tempstartDate and dtype='SYSCLOSE';
select dtype into lastType from (select dtype,dtimes from DUANTIME where to_char(dtimes, 'yyyy-MM-dd') = tempstartDate order by dtimes desc) where rownum=1 ;
sum3:=sum3+(sum2-sum1);
if lastType='SYSOPEN' then
sum3:=sum3+86400;--当午夜不关机时,最后一条为打开状态 则最后一次关机时间设为次日0点,即增叫86400(一天)秒
end if;
prm_time:=prm_time||tempstartDate||':'||sum3||',';
end loop;
exception
when others then
prm_appcode := -1;
end DUANTIME_PRC;
============数据库数据=====================
图片说明
============运行结果=====================
图片说明

1.你什么限制都没说。。。
2“其中字段status有六种状态SYSOPEN、SYSCOLOE、WAIT 、WORK 、STOP、 ALAM”中的COLOE是close吧,认真些,去修改好。


如果编程统计,按时间排序,一条一条记录读入,统计,结果依然返回成表,是很容易的,不多说。可即便这么简单,仔细想想还是有问题,如果有不合格数据怎么办?例如连续两个开机记录中间的关机记录丢失。因为你没有说,所以只能认为数据已经是处理过的合格数据。

如果使用sql,估计这才是你的本意。前面已经有了许多详细的回答,我说说思路作为补充吧。

  1. 按时间排序
  2. 过滤其他状态,只保留开机和关机两种状态的记录。这时因为数据为合格数据,奇数行一定是开机时间,偶数行一定是关机时间。
  3. 这时我们得到了一个一列多行的表,可是这时数据依然不合用。例如三年前我开机一小时,然后一直不开机,直到今天我又开机一小时,数据表为4行一列,而我们要得到一个一千多行的数据集,虽然中间的数据都是0。道理上同前面大家提到的午夜问题是一样的。是不是直接用sql生成这些行我不知道,不过我会放在前期处理,在每天的午夜加入两条开/关机记录或两条关/开机记录。
  4. 然后,没然后了,限定区间按日分组统计就完了。