2

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

我将 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)
4

2 回答 2

2

我通常看到像这样的数据模型,范围的起点是唯一被跟踪的,终点是隐含的。所以会是

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

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

于 2010-03-29T15:09:53.813 回答
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.

于 2010-03-29T20:24:49.373 回答