加入2个表来计算时差

时间:2015-05-12 08:37:55

标签: sql oracle

我们有几个单独的事件表。 对于给定的id,我们想知道2个事件之间的时差。 现在,对于给定的id,可能有几个相同的事件,我们只对“下一个”事件感兴趣。

示例:

http://sqlfiddle.com/#!4/1f724/6/0

模式

create table event_a (
  timestmp timestamp(3),
  id       varchar2(50)
);

create table event_b (
  timestmp timestamp(3),
  id       varchar2(50)
);

insert into event_a values (to_timestamp('2015-05-12 10:22:00', 'YYYY-MM-DD HH24:MI:SS'), 'x');
insert into event_b values (to_timestamp('2015-05-12 10:22:05', 'YYYY-MM-DD HH24:MI:SS'), 'x');
insert into event_a values (to_timestamp('2015-05-12 10:22:08', 'YYYY-MM-DD HH24:MI:SS'), 'x');
insert into event_b values (to_timestamp('2015-05-12 10:22:10', 'YYYY-MM-DD HH24:MI:SS'), 'x');

查询

这是我提出的查询,但在我看来有点过于复杂。我想知道是否有更好的方法来做到这一点。

如果这些表中有大量数据,此查询也需要很长时间才能运行。

select a.id, nvl((extract(day from (b.timestmp - a.timestmp))   * 86400
                 + extract(hour from (b.timestmp - a.timestmp))   * 3600 
                 + extract(minute from (b.timestmp - a.timestmp)) * 60   
                 + extract(second from (b.timestmp - a.timestmp)) ), 0) as duration_in_sec
from event_a a
join event_b b on a.id = b.id and b.timestmp = (
  select min(timestmp)
  from event_b
  where id = a.id
  and timestmp >= a.timestmp
)

3 个答案:

答案 0 :(得分:2)

你可以尝试这个,看看它是否有效/表现更好:

Select a.id, 86400 * (min(b.timestmp) - a.timestmp) diff
From event_a a
Join event_b b on a.id = b.id and b.timestmp >= a.timestmp
Group by a.id, a.timestmp

如果这对您不起作用,那么您几乎可以使用Group by:

进行旧查询
Select a.id, nvl((extract(day from (min(b.timestmp) - a.timestmp))   * 86400
                 + extract(hour from (min(b.timestmp) - a.timestmp))   * 3600 
                 + extract(minute from (min(b.timestmp) - a.timestmp)) * 60   
                 + extract(second from (min(b.timestmp) - a.timestmp)) ), 0) as duration_in_sec
From event_a a
Join event_b b on a.id = b.id and b.timestmp >= a.timestmp
Group by a.id, a.timestmp

答案 1 :(得分:2)

此解决方案应该更快,因为它没有自连接子查询:

select id, extract(day from (d)) * 86400 + extract(hour from (d)) * 3600 
         + extract(minute from (d)) * 60  + extract(second from (d)) duration
  from (
    select a.id, b.timestmp - a.timestmp d,
        row_number() over (partition by a.id, a.timestmp order by b.timestmp) rn
      from event_a a 
      join event_b b on a.id = b.id and a.timestmp <= b.timestmp
      order by a.timestmp)
  where rn = 1

SQLFiddle

答案 2 :(得分:1)

如果event_a和event_b的时间戳总是替代,那么您可以使用:

SQLFIDDLE

WITH times AS (
  SELECT id, timestmp, 1 AS event_type FROM event_a
  UNION ALL
  SELECT id, timestmp, 2 AS event_type FROM event_b
  ORDER BY 1,2,3
),
timediffs AS (
  SELECT id,
         timestmp - LAG( timestmp ) OVER ( PARTITION BY id ORDER BY timestmp ASC, event_type ASC ) AS d,
         event_type
  FROM   times
)
SELECT id,
       extract(day from (d)) * 86400
        + extract(hour from (d)) * 3600 
        + extract(minute from (d)) * 60
        + extract(second from (d)) AS duration
FROM   timediffs
WHERE  event_type = 2;