2009-04-01 14 views
2

マスタテーブルと他のテーブルのフィールドが変更されるかどうかを記録する履歴テーブルを持つことにより、ポイントインタイム情報を取得しようとするデータベースがあります。例えば対応する値が他のテーブルに存在しない場合のSQL選択値

表:社員

Id | Name  | Department 
----------------------------- 
0 | Alice  | 1 
1 | Bob  | 1 

表:歴史、その従業員0(アリス)を記録

ChangeDate | Field  | RowId | NewValue  
--------------------------------------------- 
05/05/2009 | Department | 0  | 2 

は2009年5月5日に部門2に移動します。

特定の日付に従業員の部門を特定するためのクエリを作成したいと考えています。だから、する必要があります:

  • は何も存在しない場合、マスター従業員表に、現在値がデフォルトに指定された日付
  • 前に最初の歴史のそのフィールドのレコードと従業員を探します。

どうすればいいですか?私の直観は、適切な履歴レコードがすべて日付順とマスタテーブルの最後にある結果セットの最初の行を選択することです(適切な履歴レコードがない場合は最初の結果になります)。しかし、これを実現するために必要なSQL-fuがあります。


注:私は、これがこのシステムを実装するための最良の方法ではないかもしれないことを意識しています - 私は、短期的にはこれを変更することはできないです - あなたはこの私を実装するためのより良い方法を提案することができるかどうもののそれを聞いてうれしいです。両方OracleMS SQL

+0

あなたはどのようなRDBMSを使用していますか? – Quassnoi

+0

ほとんどMSSQLですが、Oracleもサポートしていますので、可能な限り一般的なものにする必要があります。 –

答えて

2
SELECT COALESCE (
     (
     SELECT newValue 
     FROM history 
     WHERE field = 'Department' 
       AND rowID = ID 
       AND changeDate = 
       (
       SELECT MAX(changedate) 
       FROM history 
       WHERE field = 'Department' 
         AND rowID = ID 
         AND changeDate <= '01/01/2009' 
       ) 
     ), department) 
FROM employee 
WHERE id = @id 

、あなたもこれを使用することができます。しかし

SELECT COALESCE(newValue, department) 
FROM (
     SELECT e.*, h.*, 
       ROW_NUMBER() OVER (PARTITION BY e.id ORDER BY changeDate) AS rn 
     FROM employee e 
     LEFT OUTER JOIN 
       history h 
     ON  field = 'Department' 
       AND rowID = ID 
       AND changeDate <= '01/01/2009' 
     WHERE e.id = @id 
     ) 
WHERE rn = 1 

注意、ROWIDが予約語であることをOracleに、あなたが移植するときに、この列の名前を変更する必要がありますので、 。

+0

ありがとうございました。最初の解決策では、SELECT MAX(変更)サブクエリで 'AND rowID = ID'の後に 'AND changeDate <@PITDate'を追加しました。パフォーマンスを比較するために、2番目のソリューションも試してみます。ありがとう –

+0

確かに、それを逃した。 – Quassnoi

1

これは動作するはずです:

select iif(history.newvalue is null, employee.department, history.newvalue) 
as Department 
from employee left outer join history on history.RowId = employee.Id 
and history.changedate < '2008-05-20' // (i.e. given date) 
and history.changedate = (select max(changedate) from history h1 
where h1.RowId = history.RowId and h1.changedate <= history.changedate) 
関連する問題