在Oracle中查找重叠时间

时间:2014-11-11 06:50:44

标签: database oracle oracle11g

我正在编写一个查询以检测重叠时间。对于房间预订系统,如果用户输入的时隙与已经存储的任何时间和时间输出重叠,则不应进行预约。我的表格结构为:

ID      BOARDROOM_TYPE  REQUEST_TIME            USER_REQUEST    SUBJECT                  FROM_DATE  TO_DATE     FROM_TIME               TO_TIME
17174   Board Room      06/11/2014 1:21:00 AM   User A          Some Subject             11/11/2014 11/11/2014  01/11/2014 2:30:00 PM   01/11/2014 5:00:00 PM
17172   Board Room      06/11/2014 12:50:58 AM  User B          Meeting                  11/11/2014 11/11/2014  01/11/2014 9:00:00 AM   01/11/2014 1:00:00 PM

现根据这些数据,房间预留时间为上午9点至下午1点,然后是下午2:30至下午5点。

我在同一房间内检查同一日期重叠会议时间的查询是:

select count(*) from meeting_data where not (to_time <= to_date('13:00','hh24:mi:ss') and from_time >= to_date('14:00','hh24:mi:ss')) and trunc(from_date) = trunc(Sysdate) and boardroom_type = 'Board Room' and deleted = 'N'  

当timeIn = 13:00且timeOut = 14:00时,它返回2,如果count > 0,则不应插入数据。到目前为止工作正常。

问题在于,当我输入重叠时间时,如timeIn = 09:00 timeOut = 14:00,它仍然会提供2,并且自count > 0后插入即使已经在此时段中进行预订(ID = 17172)。

我的查询出错了什么?

3 个答案:

答案 0 :(得分:2)

select count(*) from meeting_data 
where NOT (
      to_date(to_char(to_time, 'YYYYMMDD') || '13:00','YYYYMMDDhh24:mi')
      not between from_time and to_time
  and to_date(to_char(to_time, 'YYYYMMDD') || '14:00','YYYYMMDDhh24:mi')
      not between from_time and to_time
  and to_time not between to_date(to_char(to_time, 'YYYYMMDD') || '13:00','YYYYMMDDhh24:mi')
                      and to_date(to_char(to_time, 'YYYYMMDD') || '14:00','YYYYMMDDhh24:mi')  
  )
  and from_date between trunc(Sysdate) and trunc(Sysdate+1) -1/24/60/60 
  and boardroom_type = 'Board Room' and deleted = 'N';

前三个条件检查是否与[from_date,to_date]没有交叉点+检查[from_date,to_date]是否不在所需的时间间隔内

您的查询中也出现了问题:

The default date values are determined as follows:
- The year is the current year, as returned by SYSDATE.
- The month is the current month, as returned by SYSDATE.
- The day is 01 (the first day of the month).
- The hour, minute, and second are all 0.

因此to_time <= to_date('13:00','hh24:mi:ss')可能会给您带来不受欢迎的结果,具体取决于您执行此比较的日期。

使用trunc(from_date) = trunc(Sysdate)进行微小更改我删除了列上的一个函数(这是一个很好的索引候选者)

如果间隔[09:00 - 13:00]和[13:00 - 14:00]被认为没有相交,那么您可以使用不严格的比较:

更改

some_date not between from_time and to_time

some_date <= from_time or some_date >= to_time

以下是修改过的查询:

select count(*) from meeting_data 
where (to_date(to_char(from_date, 'YYYYMMDD') || '13:00','YYYYMMDDhh24:mi') > from_date
       and to_date(to_char(from_date, 'YYYYMMDD') || '13:00','YYYYMMDDhh24:mi') < to_date
   or to_date(to_char(from_date, 'YYYYMMDD') || '14:00','YYYYMMDDhh24:mi') > from_date
      and to_date(to_char(to_time, 'YYYYMMDD') || '14:00','YYYYMMDDhh24:mi') < to_date
   or to_time > to_date(to_char(to_time, 'YYYYMMDD') || '13:00','YYYYMMDDhh24:mi')
      and to_time < to_date(to_char(to_time, 'YYYYMMDD') || '14:00','YYYYMMDDhh24:mi')
      )            
  and from_date between trunc(Sysdate) and trunc(Sysdate+1) -1/24/60/60 
  and boardroom_type = 'Board Room' and deleted = 'N';

答案 1 :(得分:0)

据我了解您的问题,您需要检查用户输入的数据库值。所以我认为存储过程是这里的方式。您可以将用户输入的值传递给SP,并且检查时间是否重叠。

CREATE OR REPLACE PROCEDURE check_date_clash (
  p_start_date IN DATE,
  p_end_date   IN DATE,
  l_count      OUT NUMBER
)
AS

BEGIN
  SELECT COUNT(*)
  INTO   l_count
  FROM   meeting_data
  WHERE  from_time <= p_end_date
  AND    to_time   >= p_start_date
  AND    trunc(from_date) = trunc(Sysdate) 
  AND    boardroom_type = 'Board Room'
  AND    deleted = 'N';

END check_date_clash;
/

这将使用用户输入的时间段计算重叠记录并返回计数。

答案 2 :(得分:0)

为什么不使用交叉连接,它将获得现有时间轴之间的记录 SELECT COUNT(*)FROM MEETING_DATA A,MEETING_DATA B WHERE A.FROM_TIME&gt; B.FROM_TIME和A.FROM_TIME&lt; B.TO_TIME AND ......;