如果两列之间的日期相交,则在Oracle上创建唯一索引的最有效方法

时间:2014-04-10 07:39:34

标签: sql oracle

我们假设我有一张桌子:

CREATE TABLE "STACK_OVERFLOW_QUESTION"
  (
    "SSN" VARCHAR2(13 BYTE) NOT NULL ENABLE,
    "IRN" VARCHAR2(11 BYTE) NOT NULL ENABLE,
    "BEGIN_DATE" DATE,
    "END_DATE" DATE
  )

我需要一个唯一的索引来强制执行一个策略,在该策略中,从BEGIN_DATE到END_DATE的间隔之间不能有相同的SSN和IRN。例如,让我们假设表中有这些行:

|     SSN    |     IRN     |  BEGIN_DATE  |  END_DATE   |
|------------|-------------|--------------|-------------|
| 565654     | 154646678   | 01/01/2010   | 01/02/2010  | - (first row inserted) OK
| 565654     | 154646678   | 03/04/2010   | 20/04/2010  | - (second row inserted) OK
| 565654     | 154646678   | 28/01/2010   | 13/02/2010  | - (third row inserted) ERROR

第三行违反了唯一索引。因为28/01/201013/02/2010的时间间隔与01/01/201001/02/2010相交。

处理此问题的最有效方法是什么?

1 个答案:

答案 0 :(得分:4)

看看我对这个问题的回答: Adding constraints using subquery from other table

基本思想是编写一个标识和计算坏行的查询。将该查询转换为物化视图,并添加一个检查约束,只要坏行的nr大于0,该约束就会失败。

对您的表的查询看起来像这样:

select count(*) as bad_rows
  from stack_overflow_question a
  join stack_overflow_question b using(ssn, irn)
 where a.rowid < b.rowid 
   and (   a.begin_date between b.begin_date and nvl(b.end_date, a.begin_date)
        or b.begin_date between a.begin_date and nvl(a.end_date, b.begin_date)
       );