如何使用SQL

时间:2017-04-27 18:23:44

标签: oracle group-by max min connect-by

我需要帮助计算进程间的停机时间。它需要按IMPORTID分组,然后按IMPORTREQUESTID分组。 IMPORTREQUESTID对应于IMPORTID请求中的不同阶段。因此,例如在下面的数据集中,我需要我的SQL查询在IMPORTREQUESTID中找到最高最新 ENDDATE,然后从中减去STARTDATE(最低)的下一行或者更确切地说下一组IMPORTREQUESTID的最小值(STARTDATE)。我已经对查询进行了排序,以降序排列IMPORT ID和IMPORTREQUEST ID。我应该使用“CONNECT BY”吗?在IMPORTREQUESTID的下一个直接行或集群中,在IMPORTID和IMPORTREQUESTID行中分组并找到最高ENDDATE然后从中减去最低STARTDATE的最佳方法是什么?基本上,我试图计算过程完成和下一个过程开始之间的间隔时间。有关样本数据,请参见下表:

IMPORTID IMPORTREQUESTID    STARTDATE       ENDDATE
1156     63833              4/23/2017 18:18 4/23/2017 18:18
1156     63833              4/23/2017 18:18 4/23/2017 18:18
1156     63832              4/23/2017 17:56 4/23/2017 17:57
1156     63832              4/23/2017 17:56 4/23/2017 17:57
1156     63832              4/23/2017 17:56 4/23/2017 17:57

预期结果:上述查询将返回给我的整个行集获得的所有差异的总和,最后显示每个IMPORTID:

ImportID  TOTAL Downtime        
1156          21 mins

或更好:

详细分解每个唯一的IMPORTREQUESTID(上行的结束行和下行的开始日期)之间的间隔(以秒为单位),并返回以下唯一行(相的最大ENDDATE和下一阶段的前进min(startdate)) ):

IMPORTID IMPORTREQUESTID  STARTDATE        ENDDATE          DIFF
1156      63833           4/23/2017 18:18  4/23/2017 18:18  21 mins
1156      63832           4/23/2017 17:56  4/23/2017 17:57

2 个答案:

答案 0 :(得分:0)

这样的东西?我还没有完全理解这个问题..特别是61秒来自我得到21分钟。我也不知道你为什么在你的例子中重复数据....所以我使用distinct删除了它。

这里有两个要点。

1)LEAD是一个窗口函数,它让我们可以预览定义的顺序序列中的下一条记录。我们也可以“PARTITION”,这样除非ImportId和ImportRequestID匹配,否则每个系列都不会向前看

Round((EndDate-LEAD(EndDate) over (order by ImportID, ImportRequestID DESC))*60*24)
会成为

Round((EndDate-LEAD(EndDate) over (PARTITION BY IMPORTID order by ImportRequestID DESC))*60*24)

2)我使用distinct来消除看似重复的记录;但我怀疑你的数据集确实有重复,所以可能不需要它;或者你的连接不完整会导致重复。

 With CTE (IMPORTID, ImportRequestID, StartDate, EndDate) as (
SELECT 1156,     63833, to_date('4/23/2017 18:18','MM/DD/YYYY HH24:MI'), to_date('4/23/2017 18:18','MM/DD/YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1156,     63833, to_date('4/23/2017 18:18','MM/DD/YYYY HH24:MI'), to_date('4/23/2017 18:18','MM/DD/YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1156,     63832, to_date('4/23/2017 17:56','MM/DD/YYYY HH24:MI'), to_date('4/23/2017 17:57','MM/DD/YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1156,     63832, to_date('4/23/2017 17:56','MM/DD/YYYY HH24:MI'), to_date('4/23/2017 17:57','MM/DD/YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1156,     63832, to_date('4/23/2017 17:56','MM/DD/YYYY HH24:MI'), to_date('4/23/2017 17:57','MM/DD/YYYY HH24:MI') FROM DUAL)

SELECT ImportID
     , ImportRequestID
     , to_char(StartDate,'MM/DD/YYYY HH24:MI') StartDate
     , to_char(EndDate,'MM/DD/YYYY HH24:MI') EndDate
     , Round((EndDate-LEAD(EndDate) over (order by ImportID, ImportRequestID DESC))*60*24) as Minutediff 
FROM (SELECT DISTINCT ImportID
     , ImportRequestID
     , StartDate
     , EndDate
     From CTE) B

enter image description here

答案 1 :(得分:0)

您可以通过importid和importrequestid对数据进行排序,以确保它们按照正确的时间顺序排列。然后如xQbert所述,使用lead()或lag()为结束日期时间和下一个进程的开始日期时间创建列。

lag(enddate, 1) over (order by importrequestid) as priorend

然后使用类似下面的函数来查找差异。

create or replace function timestamp_diff_in_seconds (ts1 in timestamp, ts2 in timestamp)
       return number is total_secs number;
       diff interval day(9) to second(6);
   begin
   diff := ts2 - ts1;
   total_secs := abs(extract(second from diff) + extract(minute from diff)*60 + extract(hour from diff)*60*60 + extract(day from diff)*24*60*60);

   return total_secs;
end timestamp_diff_in_seconds;

然后调用函数示例...

select timestamp_diff_in_seconds(priorend, startdate) as downtime.