自动调整范围表

时间:2010-03-29 14:28:58

标签: sql database oracle range overlap

我有一个包含开始日期范围,结束日期范围和其他一些其他列的表格。在输入新记录时,我想自动调整任何重叠的日期范围(缩小它们,拆分它们或删除它们以允许新的输入 - 参见下面的算法)。我还想确保不会意外地将重叠记录插入此表中。

我正在使用Oracle和Java作为我的应用程序代码。我应该如何强制防止重叠日期范围,还允许自动调整重叠范围?我应该创建一个AFTER INSERT触发器,使用dbms_lock来序列化访问,以防止重叠数据。然后在Java中,应用逻辑来自动调整所有内容?或者该部分应该在存储过程调用中的PL / SQL中?这是我们对其他几个表所需要的东西,所以摘要很好。

如果有人已经写过这样的内容,请分享:)

我确实找到了这个参考:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:474221407101

以下是一个示例,说明如何处理4个重叠案例中的每一个以便在插入时进行调整:

= Example 1 =
In DB (Start, End, Value):
(0, 10, 'X')
**(30, 100, 'Z')
(200, 500, 'Y')

Input
(20, 50, 'A')
Gives
(0, 10, 'X')
**(20, 50, 'A')
**(51, 100, 'Z')
(200, 500, 'Y')


= Example 2 =
In DB (Start, End, Value):
(0, 10, 'X')
**(30, 100, 'Z')
(200, 500, 'Y')

Input 
(40, 80, 'A')
Gives
(0, 10, 'X')
**(30, 39, 'Z')
**(40, 80, 'A')
**(81, 100, 'Z')
(200, 500, 'Y')


= Example 3 =
In DB (Start, End, Value):
(0, 10, 'X')
**(30, 100, 'Z')
(200, 500, 'Y')

Input
(50, 120, 'A')
Gives
(0, 10, 'X')
**(30, 49, 'Z')
**(50, 120, 'A')
(200, 500, 'Y')


= Example 4 =
In DB (Start, End, Value):
(0, 10, 'X')
**(30, 100, 'Z')
(200, 500, 'Y')

Input
(20, 120, 'A')
Gives
(0, 10, 'X')
**(20, 120, 'A')
(200, 500, 'Y')

算法如下:

given range = g; input range  = i; output range set = o

if i.start <= g.start
  if i.end >= g.end
    o_1 = i
  else
    o_1 = i
    o_2 = (i.end + 1, g.end)
else
  if i.end >= g.end
    o_1 = (g.start, i.start - 1)
    o_2 = i
  else
    o_1 = (g.start, i.start - 1)
    o_2 = i
    o_3 = (i.end + 1, g.end)

2 个答案:

答案 0 :(得分:2)

我一般都会看到数据模型,其中范围的起点是唯一被跟踪的模型,其中结束点是隐含的。所以它是

CREATE TABLE MY_TABLE
(START_AT    NUMBER,
 VALUE       NUMBER,
 CONSTRAINT MY_TABLE_PK (START_AT)
);

如果您需要以现有格式显示值,则可以使用分析和物化视图,使用LEAD(START_AT) OVER (ORDER BY START_AT)(我认为这是正确的,但未经测试)来获取已解释的结束值。

答案 1 :(得分:0)

AskTom的文章提供了一个很好的示例,说明如何完成它,但请注意,此示例会锁定整个表,这会严重影响应用程序的并发性。

如果并发是你的事,你应该只添加一个序列列(ORDER选项,如果你使用RAC)并写一个这样的查询:

SELECT  *
FROM    (
        SELECT  *, rownum AS rn
        FROM    mytable
        WHERE   start_date <= :date
                AND end_date >= :date
        ORDER BY
                seq DESC
        )
WHERE   rn = 1

找出给定日期的有效范围(和其他数据)。

这将返回包含给定日期的最后一个插入范围。

通过运行维护过程可以使查询更有效率,该过程可以及时消除重叠范围(如帖子中所述)并重写查询,如下所示:

SELECT  *
FROM    (
        SELECT  *, rownum AS rn2
        FROM    (
                SELECT  *
                FROM    (
                        SELECT  *, rownum AS rn
                        FROM    mytable
                        WHERE   seq <= :lseq
                                AND start_date <= :date
                                AND end_date >= :date
                        ORDER BY
                                start_date DESC
                        )
                WHERE   rn = 1
                UNION ALL
                SELECT  *
                FROM    (
                        SELECT  *, rownum AS rn
                        FROM    mytable
                        WHERE   seq > :lseq
                                AND start_date <= :date
                                AND end_date >= :date
                        ORDER BY
                                seq DESC
                        )
                WHERE   rn = 1
                )
        ORDER BY
                seq DESC
        )
WHERE   rn2 = 1

start_dateseq上创建索引,以便快速开始工作。

后一个查询将从处理范围(已知非重叠)中选择第一个匹配范围,未处理范围(少数几个)的第一个匹配范围和两个记录中的第一个匹配范围将选择一个最高seq