Below-the-Root方式のリンクによるリストラクチャリング
次のサンプルでは、2つのマルチパス構造フラグメントを、下位フラグメントのルートの下でリンクさせます。このサンプルを検討してみると、この方式のリンクによって多様なフラグメント結合が可能になることが分かるでしょう。問題は、「ルート下へのリンクが可能であるか」と「可能な場合それはセマンティクス的にどう処理されるか」というものです。このようなリンクが可能であることは既にわかっています。なぜなら、以前の解説記事で説明した「ルート下へのリンク」と同じ原則で機能するからです。下位構造のルートもやはり階層型モデリングのリンクポイントと考えられます。
次のサンプルコードは、それぞれ「SV1」と「SV2」のプレフィックスで示されるEmp
とCust
の2つのフラグメントを分離するSQL処理です。このクエリが行うフラグメント間リンクは、Eaddr
とAddr
ノードにおけるEaddrID
とAddrID
のデータ値に対するマッチングに基づいて処理されます。そうした処理が行われると、下位レベルフラグメントのCust
ルートがデータモデリングのエントリポイントとして使用されます(図6を参照)。
SELECT SV1.EmpID, SV1.DpndID, SV2.InvID, SV2.AddrID FROM StoreView SV1 LEFT JOIN StoreView SV2 ON SV1.EaddrID= SV2.AddrID
このサンプルで興味深いのは、このクエリ処理はCust
ルートノードに基づいているのに、このノードを出力用に指定する必要はないという点です。そのため、先に触れた検討事項は、「Invoice
ノードはどう処理されるか」という問題になってきます。なぜなら、Invoice
はAddr
ノードと間接的な関係を持つだけで、その関係の基になる共通の上位レベルノード(Cust
ノード)は出力時には排除されるからです。この場合、内部的には、下位フラグメントはEaddr
ノードからその下位のCust
ルートノードまでの上位フラグメントに結び付けられます。その後、選択されなかったCust
およびEaddr
ノードを排除したノードコレクションが作成されて、Invoice
およびAddr
ノードはその次の上位レベルであるEmp
ノードに接続されます。なおノードコレクションという概念については以前の解説記事での説明も参照してください。このサンプルは、階層型オペレーションの組み合わせでどのような処理が可能となり、どのようにして階層型セマンティクスが維持されるかを例示するために用意したものです。
図6の破線の矢印は2つのフラグメント間のデータリンクを示し、実線の矢印は結果として得られる構造を示しています。
リレーションシップを用いない構造のリシェイプ
ここまでに見たサンプルで行っていたのは、データ間のリレーションシップを基に必要な結合(join)をするリストラクチャリングという処理でした。そしてこうしたデータ間のリレーションシップが利用できないケースであっても、データ構造のセマンティクスを基にして目的とするノード(群)を構造上の特定位置に移動する、という変換方法が存在します。この方式は任意構造のリシェイプを可能としますが、そこで行われる操作は先に見たリストラクチャリングとは異なる処理であり、得られる結果も異なってくるのが普通です。「リストラクチャリング」が構造中に内在するデータ間リレーションシップを基に新たなセマンティクスを導入するのに対して、「リシェイプ」ではデータの基本的なセマンティクスは保持したまま階層型構造の形態を変更することになります。つまり、目的とする構造データセマンティクスを得られるのがリストラクチャリングであり、データのセマンティクスを変えることなく目的とするデータ構造を得られるのがリシェイプという処理だと考えればいいでしょう。
単一構造のリシェイプをする際には、当該構造の複製をいくつか作成したうえで、自分自身を比較対象としたLEFT JOIN
を上位ノードに対して施し、必要とするすべてのノードあるいはフラグメントに対してこうした処理を繰り返すことで最終的な構造を形成させます。図7のサンプルは次のSQLを用いて、非線形なマルチパス構造を線形構造にリシェイプするという処理例ですが、その際に構造に内在するリレーションシップのマッチングは利用していません。
SELECT SV1.EaddrID, SV2.EmpID, SV2.DpndID FROM EmpView SV1 LEFT JOIN EmpView SV2 ON SV1.EaddrID = SV2.EaddrID
図7を見ると、リシェイプ後の構造における1つ目のルートノードはEaddr
となっているので、こうした構造を得るにあたっては最初にこのノードの移動をしておかなくてはなりません。次に行うのは当該プロセスにおける最初の比較処理であり、ここではEaddrID
を自身のコピーと比較することで、コピー間にて位置の同期をさせるという処理を行っています。こうして同期したコピーからは、LEFT JOIN
を用いて2つ目のノードとなるEmp
を取得し、Eaddr
の下にEmp
を配置させるようにします。このプロセスの要となるのは下位構造のルート下部に対するリンクですが、こうした方式が正常に機能するのは、大部分の操作における追跡対象がルート以外のノードとなるからです。
最終的にこのプロセスは、Emp
ノードに対する同期をして、Dpnd
ノードを所定の位置に配置するまで繰り返さなくてはなりません。ただし必要な全ノードを配置するに当たっては、処理のステップ数を削減するためのショートカットが存在します。このショートカットを用いない場合、最終的な構造を得るには特定数の処理ステップが常に必要であり、その数は出力する構造のノード数マイナス1となるはずです。ところが図7を見ると、Dpnd
ノードはEmp
ノードの下位に最初から配置されているので、Emp
ノードの移動時にこのノードも一緒に移動させておけば同期用の結合ステップを1つ分省略できることになります。実際、先のSQLにおけるSELECT
ステートメントではこのショートカットを利用しており、EmpID
およびDpndID
では下位レベルのSV2
プレフィックスを使用することで、両者をまとめて選択させています。
ここでも実線の四角い枠は、選択対象のアイテムを示しています。そして非選択ノードを示す破線の四角い枠は、出力される構造からは除外されます。このように組み合わされた構造における選択フィールド群を見比べることで、どのような仕組みでリシェイプが行われるかを確認してください。ここでのLEFT JOIN
は、データのモデリングおよび必要なデータの配置という2つの処理を担っているのです。
リシェイプの詳細については「ANSI SQL Semantically Controlled Any-to-Any Data Structure Reshaping」を参照してください。