同じ表階層内の表の結合

同じ階層内の複数の表を問い合せるには、NESTED TABLES句をFROM句内で使用する必要があります。

構文

nested_tables ::=
   NESTED TABLES "(" single_from_table
   [ANCESTORS "(" ancestor_tables ")"]
   [DESCENDANTS "(" descendant_tables ")"]
")"

ancestor_tables ::= nested_from_table ("," nested_from_table)*

descendant_tables ::= nested_from_table ("," nested_from_table)*

nested_from_table ::= aliased_table_name [ON or_expression]

NESTED TABLES句は、参加している表を指定し、3つのグループに分けます。最初に、ターゲット表が指定されます。次に、ANCESTORS句(存在する場合)で、表階層内のターゲット表の祖先である必要がある表の数を指定します。最後に、DESCENDANTS句(存在する場合)で、表階層内のターゲット表の子孫である必要がある表の数を指定します。各表に対して別名を指定できます(指定しない場合は、CREATE TABLE文の項で説明されているように内部的に作成されます)。別名は一意である必要があります。

意味上、NESTED TABLES句は、ターゲット表を中心とした多数の左外部結合操作と同じです。左外部結合は標準SQLで定義される操作で、すべての主要なRDBMSでサポートされます。詳しくない人向けに、この章の最後の項で簡単に説明しています。

左外部結合の実装は、標準定義と少し異なります。違いは結果の形状にあります。具体的には、NESTED TABLES句の結果は、同じタイプを持つレコードのセットであり、(a)フィールド数は参加している表の数と同じになります。(b)各フィールドは、表の1つに対応し、その表の行またはNULLのいずれかを格納します。(c)各フィールドの名前は関連付けられた表で使用される別名で、(d)フィールドは、参加している表が表階層の深さ優先走査で検出される順序で順序付けされます。

したがって、NESTED TABLESの結果では、各表の列がサブコード内でグループ化されます。対照的に、標準の左外部結合ではフラットな結果が生成されます。各結果は、フィールド数が参加している表のすべての列の合計であるレコード/タプルです。

NESTED TABLESと多数の左外部結合とのマッピングは、いくつかの例で詳しく説明されています。簡潔にするために、左外部結合のかわりにキーワードLOJを使用します。次のCREATE TABLE文から開始します。
create table A (ida integer, a1 string, primary key(ida));
create table A.B (idb integer, b1 string, primary key(idb));
create table A.B.C (idc integer, c1 integer, primary key(idc));
create table A.B.C.D (idd integer, d1 double, primary key(idd));
create table A.B.E (ide integer, e1 integer, primary key(ide));
create table A.G (idg integer, g1 string, primary key(idg));
create table A.G.J (idj integer, j1 integer, primary key(idj));
create table A.G.H (idh integer, h1 integer, primary key(idh));
create table A.G.J.K (idk integer, k1 integer, primary key(idk));

上の文により、次の表階層が作成されます。

NESTED TABLES句では、NESTED TABLESに表を含む表階層のプロジェクションとして結合ツリーを指定します。たとえば、NESTED TABLES(A.B) ancestors(A) descendants (A.B.C.D, A.B.E)の結合ツリーを次に示します。矢印は、LOJの方向を示しています(左の表から右の表へ)。

ここで、次のNESTED TABLESケースと、それに相当するLOJ操作を見てみましょう

  1. NESTED TABLES (A.B.C c ancestors(A a, A.B b));
    これは、次と同じです
    (A.B.C c LOJ A.B b ON c.ida = b.ida and c.idb = b.idb) LOJ A a
    ON c.ida = a.ida

    結合述語は、NESTED TABLES句では暗黙的であり、常に、参加している表の主キー列に存在します。

    各A.B.C行には、AとA.Bという最大で1つの一致する行があるため、結果のレコード数は、A.B.C行の数と同じになります。このことは、NESTED TABLES句に祖先のみが含まれる場合に常に該当します。この場合、操作の効果は、他の行を削除または追加せずに、一致する祖先行(存在する場合)からの列を持つターゲット表の行をデコレートすることです。

  2. NESTED TABLES (A a descendants(A.B b, A.B.C c))
    これは、次と同じです
    A a LOJ
    (A.B b LOJ A.B.C c ON b.ida = c.ida and b.idb = c.idb)
    ON a.ida = b.ida

    DESCENDANTS句のセマンティクスを説明するもう1つの方法は、表階層の項で定義された包含関係を使用することですが、結合ツリー内の子孫表のみに制限されます。Rをターゲット表の行にし、S(R)を包含関係を介してRから到達可能なすべての子孫行を含むセットにします(つまり、S(R)は、Rに適用される包含の推移的なクロージャです)。S(R)が空の場合、Rについて1つのレコードが返され、このレコードには、結合ツリー内の各子孫表のRとNULL値が含まれます。それ以外の場合は、B(R)をS(R)の境界サブセットにします。つまり、S(R)内の、結合ツリーに子孫行がないすべての行です。次に、B(R)の各行について、次のように結果が生成されます。RRはB(R)の行、Tはそれを含む表です。RRに関連付けられた結果は、RからRRへのパスのすべての行とターゲット表からTへのパスにないすべての表のNULL値を含むレコードになります。

  3. NESTED TABLES (A a descendants(A.B b, A.G g))
    これは、次と同じです
    A a LOJ
    (A.B b UNION A.G g)
    ON (a.ida = b.ida or b.ida IS NULL) and (a.ida = g.ida or g.ida IS NULL)

    ケース2の場合と同様に、ターゲット表Aは2つの子孫表と結合されます。ただし、子孫表は結合ツリーの2つの異なる分岐から派生しているため、前述のSQL式でUNION操作を使用する必要があります。このUNIONは表A.BとA.Gの行と列の両方を統合します。したがって、表A.Bにそれぞれn列を含むN行があり、表A.Gにm列を含むM行がある場合、UNIONの結果には、それぞれn + m列を含むN + M行があります。最初のN行には、m列のNULL値を含むA.Bの行が含まれます。その後のM行には、n列のNULL値を含むA.Gの行が含まれます。A行をUNION行と一致させる場合、g.idaがNULLかどうか、またはb.idaがNULLかどうかをそれぞれチェックして、UNION行が表A.BまたはA.gのいずれにあるかを区別します。

    ケース2で指定された包含ベース定義も、ここに適用されることに注意してください。

  4. NESTED TABLES (A a descendants(A.B b, A.B.C c, A.B.E e, A.G.J.K k))
    これは、次と同じです
    A a LOJ
    (
    A.B b LOJ
    (A.B.C c UNION A.B.E e)
    ON (b.ida = c.ida and b.idb = c.idb or c.ida IS NULL) and
    (b.ida = e.ida and b.idb = e.idb or e.ida IS NULL)
    UNION
    A.G.J.K k
    )
    ON (a.ida = b.ida or b.ida IS NULL) and (a.ida = k.ida or k.ida IS NULL)
    この例は、単にケース3のより複雑なバージョンです。
  5. NESTED TABLES (A.B b ancestors(A a ON a.a1 = “abc”)
    descendants(A.B.C c ON c.c1 > 10,
    A.B.C.D d,
    A.B.E e))
    これは、次と同じです
    (A.B b LOJ A a ON b.ida = a.ida and a.a1 = “abc”) LOJ
    (
    A.B.C c LOJ A.B.C.D
    ON c.ida = d.ida and c.idb = d.idb and c.idc = d.idc
    UNION
    E
    )
    ON (b.ida = c.ida and b.idb = c.idb or c.ida IS NULL) and
    (b.ida = e.ida and b.idb = e.idb or e.ida IS NULL)

    これは、すべてが含まれる例です。ANCESTOR句とDESCENDANT句の両方、およびON述語が含まれています。NESTED TABLESからLOJへのマッピングでは、以前のケースと同じパターンが使用されます。ON述語は結合述語とともに使用されます。ほとんどの場合、NESTED TABLES内のON述語は、LOJの右側の表ではローカル述語になりますが、一般にはONが隣に表示される表の祖先である表のすべての列を参照することもできます。

2つの実装制限の他に、NESTED TABLES機能は、Oracle NoSQL Database用のSQLの他のすべての機能と組み合せることができます。たとえば、NESTED TABLES問合せには、順序基準、グループ化基準、オフセットと制限なども含めることができます。この2つの制限事項は次のとおりです。
  • 順序基準とグループ化基準は、ターゲット表のフィールドに対してのみ実行できます(ORDER BY句およびGROUP BY句の項で説明するように、これらのフィールドに適切な索引が存在する場合)。
  • NESTED TABLESにDESCENDANTS句が含まれている場合、ターゲット表の主キー列を降順に並べることはできません。たとえば、問合せselect * from nested tales(A a descendants(A.B b)) order by a.ida descでは、エラーが発生します。