8.4 フレックス列(基本より詳しい説明)

二面性ビューのフレックス列に関するすべて: 使用上のルール。いつ、どこで、何のためにそれらを使用するのか。フィールド名の競合。

二面性ビューの基礎となる表には、任意の数のJSON型の列を含めることができます。表ごとに最大で1つのJSON列を、その表がビュー定義で使用される各位置にフレックス列として指定できます。特定の表がビュー定義内の1箇所でのみ使用される場合(一般的なケース)は、その表に対して使用できるフレックス列は1つのみです。ビュー定義内のN個の異なる場所で同じ表が使用されている場合は、それらの場所に表の異なるフレックス列を最大N個指定できます。

同じフレックス列を指定して、同じドキュメントの異なる場所にフィールドを指定できます。これらの異なる場所では、そのフレックス列に格納されているフィールドをすべて共有します。同じフィールドに異なる新しいフィールドや異なる値を指定しないことで、任意の場所に対する更新は一致する必要があります。

ノート:

フレックス列の場合も同じ一般的な動作が維持されます。ドキュメントの複数の場所にあるフィールドをサポートするために使用した場合、それらのすべての場所が同じデータを共有します。非フレックスの場合、フィールドのみが同じである必要があります。フィールド名は場所によって異なっても構いません。

特定の二面性ビュー定義では、同じJSON列を、あるドキュメントの場所ではフレックス列として使用し、別の場所では非フレックス列として使用することはできません。これを試みると、エラーが発生します。

どの表でも、通常、JSON列は柔軟性のあるデータを提供します。デフォルトでは、そのタイプと構造はいかなる方法でも(たとえば、JSONスキーマによって)制約/指定されません。

二面性ビューのフレックス列として指定されているJSON列の特長は次のとおりです:

  • 列値は、JSONオブジェクトまたはSQL NULLである必要があります。

    つまり、単なるJSONではなく、JSON (OBJECT)型として宣言する必要があります。そうしないと、二面性ビュー定義でその列を使用しようとするとエラーが発生します。

    (この制限は、非フレックスJSON型の列には適用されません。この値には、スカラー、配列またはオブジェクトのいずれかのJSON値を指定できます。)

  • 読取りでは、フレックス列に格納されているオブジェクトはネストされていません。結果となるドキュメント・オブジェクトに、そのフィールドが展開されます

    つまり、フレックス列の表によって生成されるオブジェクトの一部のフィールドの値として、格納されているオブジェクトは含まれません。かわりに、格納されているオブジェクトの各フィールドが、そのドキュメント・オブジェクトに含まれます。

    (非フレックスのJSON型列内の値(オブジェクト、配列またはスカラー)はそのまま含まれます。オブジェクトは、その二面性ビュー定義においてネスト解除が明示的に指定されている場合を除き、ネスト解除されません「二面性ビューの作成」を参照してください。)

    たとえば、表tab1のフレックス列の特定の行のオブジェクトにフィールドfooおよびbarがある場合、その行に対応する二面性ビュー・ドキュメントでは、tab1から生成されるオブジェクトにも、fooおよびbarのフィールドが含まれます。

  • 書込みでは、ドキュメント・オブジェクトのフィールドは格納されたオブジェクトに戻され、他の列でサポートされていないフィールドはフレックス列に自動的に追加されます。つまり、認識されないフィールドがJSONフレックス列のオブジェクトに"オーバーフロー"します。

    たとえば、新しいフィールドtotoが、フレックス列がある表に対応するドキュメント・オブジェクトに追加された場合、フィールドtotoが表によってまだサポートされていなければ、ドキュメントの挿入時にフィールドtotoがフレックス列のオブジェクトに追加されます。

ノート:

フレックスJSON型の列にオブジェクト値(またはSQL NULL)のみを保持するように要求するには、変更されたデータ型JSON (OBJECT)を使用して定義するか、{"type":"object"}のJSONスキーマVALIDATEチェック制約を使用します。『Oracle Database JSON開発者ガイド』「JSONスキーマを使用したJSONデータの検証」を参照してください。

より一般的には、フレックスJSON型の列に、スカラー、オブジェクトまたは配列のJSON値のみ、またはそれらの任意の組合せのみを保持するように要求できます。また、スカラー値を文字列や日付などの特定の型に制限できます。たとえば、列の型がJSON (OBJECT, SCALAR DATE)の場合、オブジェクトまたは日付である値のみが許可されます。

二面性ビューに対してフレックスとして指定された列は、ビューに対してのみフレックスです。属している先がの場合、通常のJSON型の列にすぎません。ただし、各行の値は単一のJSONオブジェクトまたはSQL NULLである必要があります。

したがって、異なる二面性ビューでは、同じ表に対して異なるフレックス列を(つまり、異なる名前で)定義でき、各ビューのフレックス列は、そのビュー独自の目的にあわせて、そのビューのみがサポートするドキュメントにフィールドを提供します。

ノート:

なんらかの理由で、実際に2つ以上の二面性ビューでフレックス列を共有させる場合は、各ビューを定義するときにフレックス列に同じ名前を付けるだけです。これは必要な場合もありますが、その結果に注意してください。

ビューの定義で明示的に指定された個々のフィールド専用の非フレックス列とは異なり、フレックス列にはビュー定義では不明な複数のフィールドのデータが保持されます。フレックス列は基本的に、ドキュメント内の特定の場所にある認識されない受信フィールドに対するフリー・パスです(柔軟性を提供することがその目的です)。

書込み時に、認識されないフィールドは(ドキュメント内のフィールドの場所に関連する表の)フレックス列に格納されます。同じ基礎となる表を持つ2つのビューがそこでフレックス列を共有している場合、どちらのビューでも認識されない受信フィールドはその列に格納され、読取り時にそれらのフィールドは両方のビューのドキュメントに公開されます。

フレックス列のオブジェクトが読取り時にネストされず、フィールドが表の他の列によって生成されたフィールドに追加されるため、また、JSON列がデフォルトではスキーマレスであるため、フレックス列データへの変更によって、結果のドキュメント・オブジェクトの構造およびそのフィールドの一部のタイプが変更される場合があります。

実際に、JSONオブジェクトをサポートする表に任意のレベルでフレックス列を提供することで、二面性ビューのサポート対象ドキュメントの型指定と構造をそのレベルで変更/展開できます。(別の方法では、特定のJSONフィールドの値について型指定および構造を発展させるために、フレックスのJSON型列をそれらのフィールドにマップできます。)

列の表を介してフレックス列データを直接変更することで、二面性ビューのドキュメントのタイプと構造を変更できます。さらに重要なこととして、基礎となるリレーショナル列に対応していないフィールドを含むドキュメントを挿入または更新するだけで、これを実行できます。そのようなフィールドは、対応するフレックス列に自動的に追加されます。したがって、アプリケーションは、基礎となる表にフレックス列があるオブジェクトで、任意のフィールドを含むドキュメントを自由に作成できます。

ただし、フレックス列からオブジェクトをネスト解除すると、そのフィールドと、同じ表の他の列から導出されたフィールドとの間で名前の競合が発生する可能性があることに注意してください。このような競合は、フレックス列として機能しないJSON列では発生しません。

このため、格納されているJSONオブジェクトのネストを解除する必要がない場合、オブジェクト全体をフィールドの値として含めるだけで十分であれば、その列をフレックスとして指定しないでください。リレーショナル列でサポートされているドキュメント・オブジェクトにフィールドを追加できる必要がある場合は、フレックス列を使用します。

フレックス列のすべての行の値は、JSONオブジェクトまたはSQL値がNULLである必要があります。

SQL NULLと空のオブジェクト({})は同じように動作しますが、通常、これらはドキュメントのETAG値への関与が異なります。(フレックス列にNOCHECKの注釈を付けて、ETAG計算からそのデータを削除できます。フレックス列で列注釈[NO]UPDATE[NO]CHECKを使用することもできます。)

二面性ビュー定義では、SQLでキーワードAS FLEXを使用するか、GraphQLで注釈@flexを使用してビュー定義の列名に従って、JSON型の列をビューのフレックス列として指定します。

たとえば、この二面性ビューdv1のGraphQL定義では、表table1の列t1_json_colがフレックス列として指定されます。オブジェクト値のフィールドは、field1field2の兄弟として結果のドキュメントに含まれます。(JSONオブジェクトには未定義のフィールド順序があるため、二面性ビュー定義で表の列が指定される順序は重要ではありません。)

CREATE JSON RELATIONAL DUALITY VIEW dv1 AS
  table1 @insert @update @delete
    {_id       : id_col,
     t1_field1 : col_1,
     t1_json_col @flex,
     t1_field2 : col_2};

表が複数の二面性ビューの基礎となる場合、それらのビューでは当然、表の同じ列の一部またはすべてを使用できます。このような共有表の特定の列は、このような任意の数のビューに対してフレックスとして指定することも、それ以外を指定することもできます。

二面性ビューで列がフレックス列として使用されるということは、表を更新して列値に直接変更が行われる場合、列の値はJSONオブジェクト(またはSQL NULL)である必要があるということです。

また、同じ列が別の二面性ビューの基礎となる表で使用され、そのビューのフレックス列として指定されていない場合、そのビューでは列によって生成されたJSONフィールドが結果のドキュメントに展開されません。このビューでは、これらのフィールドを含むJSONオブジェクトがそのまま含まれます。つまり、フレックス列として指定することはビュー固有です。

静的ディクショナリ・ビュー*_JSON_DUALITY_VIEW_TABSBOOLEANの列HAS_FLEX_COLをチェックすると、二面性ビューの基礎となる特定の表にフレックス列があるかどうかを確認できます。静的ディクショナリ・ビュー*_JSON_DUALITY_VIEW_TAB_COLSBOOLEANの列IS_FLEX_COLをチェックすると、基礎となる表の特定の列がフレックス列かどうかを確認できます。『Oracle Databaseリファレンス』ALL_JSON_DUALITY_VIEW_TABSおよびALL_JSON_DUALITY_VIEW_TAB_COLSを参照してください。

二面性ビューの基礎となる表内のフレックスJSON列と非フレックスJSON列の両方のデータはスキーマレスの場合があり、デフォルトでも同様です。

ただし、JSONスキーマは、二面性ビュー定義の任意の場所で使用されるJSON型の列に適用して、その柔軟性を削除(ロック)できます。JSONスキーマは、二面性ビューによって生成またはサポートされているドキュメントに組み込むこともできます。

フレックス列内のオブジェクトのフィールドは結果のドキュメントに展開されるため、JSONスキーマをフレックス列に適用すると、DMLを使用してそのオブジェクトの各フィールドの個別の列をフレックス列の表に追加した場合と同様の結果になります。

二面性ビューの基になるJSON型列がフレックス列であるかどうかにかかわらず、JSONスキーマをそれに適用することで、データの論理構造、つまりそのビューでサポートされているドキュメントの構造を変更します。一部のスキーマ柔軟性は削除しますが、格納構造(表)は変更しません。

フレックス列で生成されるフィールド名の競合

フレックス列のフィールドは、フィールドが指定されているオブジェクトに展開されるため、フィールド名の競合が発生する可能性があります。このようなことが発生するのは、次のような状況です:

  • 二面性ビューの基礎となる表が再定義され、新しい列が追加されます。二面性ビューが再定義され、新しい列に対応するJSONフィールドに、同じ表のフレックス列にすでに存在するフィールドと同じ名前が付与されます。

    問題: 非フレックス列に関連付けられたフィールド名は、フレックス列データのフィールドと同じになります。

  • フレックス列が直接更新され(つまり、ビューでサポートされているドキュメントを更新しない)、ビュー定義に対応するフィールドと同じ名前のフィールドが基礎となる同じ表の別の列に追加されます。

    問題: 非フレックス列に関連付けられたフィールド名は、フレックス列データでも使用されます。

  • 2つの二面性ビューdv1およびdv2は、同じ列jcolをフレックスとして使用して基礎となる表を共有します。dv1のみが、表の非フレックス列foocolを使用し、関連付けられたフィールドfooに名前を付けます。

    データがdv1に挿入され、列foocolが移入されます。これは、表に行を挿入するか、フィールドfooを含むドキュメントをdv1に挿入することによって発生する可能性があります。

    dv2にドキュメントを挿入すると、フィールドfooのJSON行がフレックス列に追加されます。

    問題: ビューdv2に問題はありません。ただし、ビューdv1のフィールド名fooは非フレックス列に関連付けられており、フレックス列データでも使用されます。

データベースでこのような競合の発生を防止することは実行可能ではありませんが、読取り(選択、取得、JSON生成)操作中に検出された場合に、その競合の処理に望ましい動作を指定できます。(このような競合はすべて、読取り時に検出されます。)

これは、フレックス列宣言の最後に次のキーワードを使用して実行します。エラーを発生させないすべてのケースでは、競合するフィールド名は非フレックス列から読み取られます。つまり、優先度は常に非フレックス列に指定されます。

GraphQL SQL 動作

(conflict: KEEP_NESTED)

KEEP [NESTED] ON [NAME] CONFLICT

(キーワードNESTEDおよびNAMEはオプションです。)

競合するフィールド名は、非フレックス列から読み取られます。フィールド_nameConflicts (予約名)が追加され、値とともにメンバーが競合する名前とその値であるオブジェクトがフレックス列から取得されます。

これがデフォルトの動作になります。

たとえば、特定のドキュメントについて、非フレックス・フィールドquantityに値100があり、フレックス列データに値"314"のフィールドquantityがある場合、非フレックス・フィールドquantityはその値100を保持し、フィールド_nameConflictsはメンバー"quantity":314を含むように作成または変更されます。

(conflict: ARRAY)

ARRAY ON [NAME] CONFLICT

(キーワードNAMEはオプションです。)

競合するフィールド名は、非フレックス列から読み取られます。競合がある各名前の値は非フレックス列で、要素が値である配列に変更されます。1つは非フレックス列で、もう1つはフレックス列データで、その順序で変更されます。

たとえば、特定のドキュメントについて、非フレックス・フィールドquantityの値が100で、フレックス列データに値が"314"のフィールドquantityがある場合、非フレックス・フィールドquantityの値は配列[100,314]に変更されます。

(conflict: IGNORE)

IGNORE ON [NAME] CONFLICT

(キーワードNAMEはオプションです。)

競合するフィールド名は、非フレックス列から読み取られます。フレックス列の同じ名前は無視されます。

(conflict: ERROR)

ERROR ON [NAME] CONFLICT

(キーワードNAMEはオプションです。)

エラーが発生します。

たとえば、このGraphQLフレックス宣言では、列extrasをフレックス列として定義し、そのフィールド名から発生する可能性のある競合が、単にフレックス列データの問題のあるフィールドを無視することによって処理されるように指定します:

extras: JSON @flex (conflict: IGNORE)

ノート:

IGNORE ON CONFLICTおよびARRAY ON CONFLICTは、ETAGチェックと互換性がありません。ETAGがチェックされ、これらの競合の宣言のいずれかがあるフレックス列を含む二面性ビューを作成しようとすると、エラーが発生します。

ノート:

非表示フィールドの名前が、同じ表のフレックス列に格納されているフィールドの名前と競合する場合、二面性ビューでサポートされるドキュメントでは、その表に対応するJSONオブジェクトからのフィールドは存在しません