查询从任务数据中隔离进程

时间:2014-10-14 10:18:14

标签: sql oracle

我在某些流程中有以下任务表:

ID  | PREV_ID | NEXT_ID | TASK_TS
----+---------+---------+--------------------
100 |         |   101   | 2013-01-10 10:22:00
101 |   100   |   102   | 2013-01-10 10:25:12
102 |   101   |         | 2013-01-10 10:27:00
103 |         |   104   | 2013-01-10 10:31:00
104 |   103   |         | 2013-01-10 10:35:00
105 |         |         | 2013-01-10 10:38:22

ID是任务ID,PREV_ID是进程链中先前任务的ID,NEXT_ID是进程链中下一个任务的ID,TASK_TS是任务(事件)发生时的时间戳。

我需要查询来隔离此表中用启动任务ID表示的进程,计算进程中的任务数和进程持续时间(进程任务链中最后一个和第一个任务之间的差异),以分钟/小时/天为单位(并不重要。

ID  |  TASKS | DURATION
----+--------+---------
100 |    3   |    5      <-- this process has 3 tasks and lasted 5 mins
103 |    2   |    4      <-- this process has 2 tasks and lasted 4 mins
105 |    1   |    0      <-- this process has only 1 task and lasted 0 mins

1 个答案:

答案 0 :(得分:1)

您可以使用分层查询来查找每个链的根ID(即第一个任务):

select t.*, connect_by_root id as root_id
from t42 t
connect by id = prior next_id
start with prev_id is null;

        ID    PREV_ID    NEXT_ID TASK_TS                         ROOT_ID
---------- ---------- ---------- ---------------------------- ----------
       100                   101 10-JAN-13 10.22.00.000000000        100 
       101        100        102 10-JAN-13 10.25.12.000000000        100 
       102        101            10-JAN-13 10.27.00.000000000        100 
       103                   104 10-JAN-13 10.31.00.000000000        103 
       104        103            10-JAN-13 10.35.00.000000000        103 
       105                       10-JAN-13 10.38.22.000000000        105 

这使用connect_by_root operator

  

CONNECT_BY_ROOT是一元运算符,仅在分层查询中有效。使用此运算符限定列时,Oracle将使用根行中的数据返回列值。此运算符扩展了分层查询的CONNECT BY [PRIOR]条件的功能。

因此,无论层次结构中的层次是多少,您仍然可以看到它与哪个根相关。在这种情况下,前三行都与根ID 100相关,例如;在没有遍历层次结构的情况下,对于ID 102来说并不明显。

然后,您可以将该分层查询用作基于根ID分组的子查询:

select root_id as id, count(*) as tasks,
  max(task_ts) - min(task_ts) as duration
from (
  select t.*, connect_by_root id as root_id
  from t42 t
  connect by id = prior next_id
  start with prev_id is null
)
group by root_id
order by root_id;

        ID      TASKS DURATION  
---------- ---------- -----------
       100          3 0 0:5:0.0   
       103          2 0 0:4:0.0   
       105          1 0 0:0:0.0   

此处的持续时间是一个时间间隔(一天到一秒),因为我将task_ts列设为时间戳。如果你的确是一个约会,那么你将会看到一天中的一小部分。无论哪种方式,您都可以将其转换为您想要的格式。

SQL Fiddle with timestampswith dates