-製品価格
-通貨レート
-投稿
など また、1つの定期的な情報が頻繁に変更され、もう1つはめったに変更されません。 めったに変更されない情報に起因する可能性があります、例えば:
-姓と名
-住所
-家族のステータス
そのため、ほとんどの場合、このめったに変更されない情報の変更履歴を保持する必要はありません。 誰も過去にさかのぼってレポートを作成し、レポートの日付に有効なこの情報を表示することはありません。
そのような場合、情報が変更されたという事実、以前の値、および変更の日付を保存するだけで十分です-これはまれなケースで必要です。
次に、そのようなレポートがシステムで明らかに必要であり、特定の日に関連データの受信が必要な場合に備えて、リレーショナルデータベースに定期的な情報を保存する方法について説明します。
たとえば、人に関する情報を取得します。
"". :
-
-
-
-
-
-
-
ここで時間内に変更できる詳細は、理論的には次のとおりです。姓、名、家族の状況、住所、そして正直なところ、ポール。
このデータの変更履歴を保存するオブジェクトを作成します。 変更するすべての詳細を含むレコード全体を保存することにすぐに同意します。これは仕事に便利です。 データ量を失いますが、処理で勝ちます。
「Person」オブジェクトから変数の詳細を取り出し、定期的な情報を保存するためのオブジェクトを作成します。
"". :
-
-
" ". :
-
-
-
-
-
-
-
(実際、PersonからDetailsにすべての詳細を転送できます。ここでの目標は、これが不要であることを示すことです)
情報オブジェクトは、「情報の変更日」の存在と、主要なPersonオブジェクトへのリンクによって区別されます。
システムのすべてのオブジェクトでは、「Person」オブジェクトとそのオブジェクトへのリンクを使用する必要があり、情報は、それらへの直接リンクのない従属オブジェクトとしてのみ使用されます。
それはすべてのようですか?! しかし、それだけのようです。
人のリストを表示しようとすると、すぐに問題が始まります。 これを行うクエリを作成してみましょう。 イマジネーションを含め、ロシア語でオブジェクトSQLを提示します。
select ., ., .
from ,
where .ID = .
しかし、ここに問題がすぐにあります-私たちはその人に関する情報の全歴史を見ます。 そして、現在の日付に関連する情報を持つ人々のリストが必要です。 要件への適応:
select ., ., .
from ,
where .ID = .
and .ID = (select top 1 .ID from where .ID = . and . <= order by . desc)
結果は正しくなりましたが、クエリに非常に長い時間がかかり、大容量ではDBMSを完全に無効にすることができます。 多数のサブクエリが実行されています。
彼らが言うように、代替手段があります-アヒル! 前述のように、データの冗長性を確保することをお勧めしますが、データを処理するときにパフォーマンスを低下させることは避けてください。
1つの日付を登録に追加します。
" ". :
-
-
-
-
...
したがって、この日付は、個人に関する情報の「隣接」記録の日付を示します。 このフィールドには常に値があることが重要です。 次に、次の変更日が不明な場合は、たとえば「12.31.9999」などの「最大」日付を入力します。 その結果、リクエストを次のように書き換えることができます。
select ., ., .
from ,
where .ID = .
and . >
and . <=
すべてがすでにゴージャスです!
たとえば、トリガーで次の日付を入力できます。 ここでは、「情報の変更日」および「個人」を変更し、実際にレコードを削除する可能性を考慮する必要があります。 これらのトリガーアルゴリズムは既に非常に単純です。 合計で、レコードを保存するときに、最大2つの「隣接」レコード(現在の隣接レコード1つ、新しい隣接レコード1つ)をさらに変更できます。 これは、まれな変更によるわずかな損失です。
定期的な情報の別のバージョン、たとえば、組織のコンテキストでの同じ人物の職場の場所を保存する方法を見てみましょう。
. "". :
-
-
-
-
-
現在の日付の全従業員の選択:
select ., ., ., ., .
from , ,
where .ID = .
and . >
and . <=
and .ID = .
and . <=
and . >
and . =
すべてが素晴らしく、素晴らしいです。 問題はないようです...年の初めから会社で働いていた人々を数える/撤回するように頼まれるまで?
どの従業員になるか考えてみましょう。
a)年の初めに働いた人
b)現在の日付で働いている人
c)年の初めに来て、今までに辞めた人
(簡単にするために、リクエストからPersonを削除します。すべてが明確であるため、Personの名前フィールドから利用できると仮定します)
select ., ., .
from ,
and .ID = .
and . =
and (
(. <= and . > ) /* */
or (. <= and . > ) /* */
or (. >= and . <= ) /* */
)
その結果、まったく疑わずに、この期間内に職位を変更した人や仕事を中断した人の記録をいくつか取得します。 人の繰り返しを取り除く方法は? 個別に適用しますか? 彼の最後の投稿が必要です! サブクエリを試すことができますが、より良いオプションがあります。
ここでは、個人に関する情報に似たストレージアプローチを適用することもできます。
言及する価値のあるもう1つのことは、「キーの詳細」の概念です。これは、間隔(この場合、受入日から解任日まで)のレコードが交差しない値のセットです。 従業員の場合、このセットには詳細「個人」と「組織」、つまり 1人の組織で複数のレコードを同時に持つことはできませんが、異なる組織で作業することはできます。
そのため、「次の日付」属性もキー詳細のフレームワーク内で機能します。 位置を変更すると、これらの日付は次のレコードに設定され、組織を変更すると-最大のままになります。
"". :
-
-
-
-
-
-
同じリクエストを書き換えます:
select ., ., .
from ,
and .ID = .
and . =
and (
(. <= and . > and . > ) /* */
or (. <= and . > ) /* */
or (. >= and . <= and . > ) /* */
)
これでデータが正しくなり、すべてが迅速に機能するようになりました。
また、次の日付と同様に、前の日付を追加できます。これは、前の位置または「最小」日付(01.01.0001など)を示します。 前の日付は、「最も近い従業員が現れる」などのクエリに使用されます。 トリガーの日付を変更することもできます。 さらに最大4つのエントリが変更されます。
この設計のおかげで、質問に対する答えを簡単に取得できます。
-会社で働いたことのある人(または期間)のリスト
-最近引退した日付のリスト
-日付以降に最初に決済されたリスト
-など
PS疲れないことを願う
UPD 03/28/2011
MaximKatによると、従業員のリクエストテキストを更新しました。
また、重要な詳細に関するメモを追加しました。