複数の履歴管理されるマスタを結合してマスタを作る(内部結合編)

開始日と終了日を持つ履歴管理されるマスタは、特定の日付においては一意に定まるので通常の利用であれば問題ないが、複数の履歴管理されるマスタから別の履歴管理されたマスタを生成するのはものすごく困難である。

しかし、内部結合する(=関係する履歴管理されたマスタのすべてが有効な期間のみマスタを作る)ことが前提であれば、実現する方法はある。

まず、履歴管理されたマスタを複数結合するということはどういうことかと考えると、まず、期間ごとに分けられたブロックの組み合わせに対し、重複した期間の境界で区切る必要があることに気付く。そして、重複した期間を境界で切り分けるには、期間ブロックの全組み合わせを求め、最大の開始日と最小の終了日を求めれば良いことがわかる。



例えば、履歴管理された社員マスタと履歴管理された組織マスタから履歴管理された組織構成マスタを求める場合は次のようにすれば良い。

SELECT
    IM.社員コード,
    SM.組織コード,
    GREATEST(IM.開始日, SM.開始日) AS 開始日,
    LEAST(IM.終了日, SM.終了日) AS 終了日,
    IM.社員名称,
    SM.組織名称
FROM
    社員マスタ IM
    INNER JOIN 組織マスタ SM
        ON SM.組織コード = IM.組織コード
        AND SM.開始日 <= IM.終了日
        AND SM.終了日 >= IM.開始日

ここで、注意しなければならないのは、3つ以上の履歴管理されたマスタを結合する場合だ。例えばAとB、BとCは期間が重なるが、AとCは期間が重ならない場合には、同じようにすると開始日と終了日が逆転してしまう。このような場合にはWHERE句で絞込みを行なう必要がある。

SELECT
    IM.社員コード,
    SM.組織コード,
    GREATEST(IM.開始日, KM.開始日, SM.開始日) AS 開始日,
    LEAST(IM.終了日, KM.終了日, SM.終了日) AS 終了日,
    IM.社員名称,
    KM.役職コード,
    SM.組織名称
FROM
    社員マスタ IM
    INNER JOIN 組織構成マスタ KM
        ON KM.社員コード = IM.社員コード
        AND KM.開始日 <= IM.終了日
        AND KM.終了日 >= IM.開始日
    INNER JOIN 組織マスタ SM
        ON SM.組織コード = KM.組織コード
        AND SM.開始日 <= KM.終了日
        AND SM.終了日 >= KM.開始日
WHERE
    GREATEST(
        IM.開始日, 
        KM.開始日,
        SM.開始日
    ) <= LEAST(
        IM.終了日,
        KM.終了日,
        SM.終了日
    )

※これの外部結合版が簡単に出来る方法があれば教えてください。