Oracle如何选择间隔

时间:2013-10-22 17:43:56

标签: sql performance oracle date materialized-views

想象一下带锁门的房间。门附近有读卡器。要打开门,您需要将卡放入读卡器。

我的Oracle数据库中有两个包含事件的表 - 参赛作品(门从房间外面打开) 出口(门从房间内打开)

我想要的只是选择presense的间隔 员工1在某一天从10:00到11:00以及从12:00到18:00在房间里。

但是有3个问题

  1. 有时用户打开门但不要离开房间。
  2. 有时一个用户打开门,另一个用户与他一起出去 门开了一次。
  3. 数据大小(每张表约100k)
  4. 问题:

    1. 选择presense间隔的最佳方法是什么
    2. 有没有办法创建快速可刷新的物化视图来解决这个问题?
    3. 这是样本

      drop table entries;
      drop table exits;
      
      CREATE TABLE ENTRIES
      (   
        "EVENTDATE" DATE NOT NULL, 
        "EVENTTIME" DATE NOT NULL, 
        "EMPLOYEEID" NUMBER NOT NULL
      );
      
      CREATE TABLE EXITS
      (   
        "EVENTDATE" DATE NOT NULL, 
        "EVENTTIME" DATE NOT NULL, 
        "EMPLOYEEID" NUMBER NOT NULL
      );
      
      
      delete from ENTRIES;
      delete from exits;
      
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 08:44:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:18:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:19:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:22:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:37:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:38:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:39:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:40:00','DD-MON-RR HH24:MI:SS'));
      Insert into ENTRIES (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 13:22:00','DD-MON-RR HH24:MI:SS'));
      
      Insert into EXITS   (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:40:00','DD-MON-RR HH24:MI:SS'));
      Insert into EXITS   (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 12:36:00','DD-MON-RR HH24:MI:SS'));
      Insert into EXITS   (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 11:55:00','DD-MON-RR HH24:MI:SS'));
      Insert into EXITS   (EMPLOYEEID,EVENTDATE,EVENTTIME) values (8,to_date('01-AUG-13 00:00:00','DD-MON-RR HH24:MI:SS'),to_date('01-JAN-00 18:02:00','DD-MON-RR HH24:MI:SS'));
      

      所需的结果如下:

      "EMPLOYEID"   "EVENTDATE"            "ENTERTIME"              "LEAVETIME"
      8            01-AUG-13 00:00:00    01-JAN-00 08:44:00      01-JAN-00 11:55:00
      8            01-AUG-13 00:00:00    01-JAN-00 12:18:00      01-JAN-00 12:36:00
      8            01-AUG-13 00:00:00    01-JAN-00 12:37:00      01-JAN-00 12:40:00
      8            01-AUG-13 00:00:00    01-JAN-00 13:22:00      01-JAN-00 18:02:00
      

      更新

      如果有2个连续使用,请先忽略秒。 如果连续有2个出口使用秒,则忽略第一个

2 个答案:

答案 0 :(得分:2)

请找到以下测试的查询: -

SELECT employeeid,eventdate,entry_time,exit_time FROM (SELECT employeeid,eventdate,entry_time,exit_time, rank() over (partition BY employeeid,eventdate,exit_time ORDER BY entry_time ASC) et FROM (SELECT t.employeeid,t.eventdate,t.eventtime entry_time, o.eventtime exit_time, rank() over (partition BY t.employeeid,t.eventdate,t.eventtime ORDER BY o.eventtime ASC) mt FROM entries t,exits o WHERE t.employeeid = o.employeeid AND t.eventdate=o.eventdate AND t.eventtime < o.eventtime) WHERE mt =1)WHERE et=1

你可以在http://sqlfiddle.com/#!4/72ac2/9

进行测试

答案 1 :(得分:0)

我没有测试看看是否有效,我忽略了事件时间,但尝试以下方法。 基本上,我们想要找到真正的输入和真实退出(真正的输入:输入/退出,之间没有输入,真正的退出:退出/输入,之间没有退出)。我们加入两个(加入真正的退出两次)并显示进入/退出退出后的输入/退出,输入退出之间没有其他退出。

select
  a.employee_id
, true_enterdate
, true_exitdate
from (
select
  ent1.eventdate true_enterdate  -- enter/exit with no enter between
, employee_id
from
  entries ent1
  join exits ex1 using (employee_id)
  left outer join entries ent2 using (employee_id)
where 1=1
  and ent1.eventdate < ex1.eventdate  
  and ent2.eventdate > ent1.eventdate
  and ent2.eventdate < ex1.eventdate
  and ent2.employee_id is null 
) a join (  
select
  ent1.eventdate true_exitdate  -- exit/enter with no exit between
, employee_id
from
  entries ent1
  join exits ex1 using (employee_id)
  left outer join exits ex2 using (employee_id)
where 1=1
  and ent1.eventdate < ex1.eventdate  
  and ex2.eventdate > ent1.eventdate
  and ex2.eventdate < ex1.eventdate
  and ex2.employee_id is null 
) b using (employee_id)
left outer join (
select
  ent1.eventdate true_exitdate2  -- exit/enter with no exit between
, employee_id
from
  entries ent1
  join exits ex1 using (employee_id)
  left outer join exits ex2 using (employee_id)
where 1=1
  and ent1.eventdate < ex1.eventdate  
  and ex2.eventdate > ent1.eventdate
  and ex2.eventdate < ex1.eventdate
  and ex2.employee_id is null 
) c using (employee_id)(
where 1=1
  and true_enterdate < true_exitdate
  and true_exitdate2 > true_enterdate
  and true_exitdate2 < true_exitdate
  and c.employee_id is null;