2

開始日の範囲、終了日の範囲、およびその他のいくつかの列を含むテーブルがあります。新しいレコードの入力時に、重複する日付範囲を自動的に調整したい (それらを縮小、分割、または削除して、新しい入力を可能にする - 以下のアルゴリズムを参照)。また、重複するレコードが誤ってこのテーブルに挿入されないようにしたいと考えています。

アプリケーション コードに Oracle と Java を使用しています。日付範囲の重複を防止し、重複する範囲を自動的に調整できるようにするにはどうすればよいですか? データの重複を防ぐために、アクセスをシリアル化するための dbms_lock を使用して AFTER INSERT トリガーを作成する必要があります。次に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_dateますseq

後者のクエリは、処理された範囲 (重複していないことがわかっている) から最初に一致する範囲を選択し、未処理の範囲 (少数) から最初に一致する範囲を選択し、2 つのレコードのうち、最も高いものを選択します。seq.

于 2010-03-29T20:24:49.373 に答える