7 JSONリレーショナル二面性ビューに使用されるGraphQLの言語

GraphQLは、様々なデータベースで使用できるオープンソースの汎用問合せ言語かつデータ操作言語です。JSONリレーショナル二面性ビューを作成するために、Oracle Databaseでは、GraphQLの構文および操作のサブセットがサポートされています。

この章では、GraphQLのサポートされるサブセットについて説明します。「GraphQLを使用したカーレース二面性ビューの作成」で説明されていない構文および機能について紹介します。ここでは、GraphQLを使用した二面性ビューの作成の簡単な例をいくつか示します。

GraphQLを使用した二面重ビューの作成でサポートされているOracle構文は、GraphQL仕様(2021年10月)のセクションB.1、B.2およびB.3で指定されているGraphQLの適切なサブセットです。ただし、ユーザーが指定した名前は、ここで指定するOracle固有のルールを満たす必要があります。

Oracle GraphQL構文には、JSONリレーショナル二面性ビューでの使用を容易にするための追加のオプション機能もあります。GraphQLをプログラムで使用する必要があり、標準のGraphQL構文の使用を続ける場合、これを実行できます。その必要がない場合は、オプションの構文機能が便利なことがあります。

GraphQLをよく理解している読者の場合、サポートされている言語のサブセットには、次の標準のGraphQL構文は含まれていません:

  • ミューテーションとサブスクリプション。サポートされる操作は問合せのみです。

  • インライン・フラグメント。事前定義済のFragmentSpread構文のみがサポートされています。

  • 型定義(型インタフェース、共用体、列挙型、入力オブジェクト、および型拡張)。GraphQLオブジェクトおよびスカラーの型定義のみがサポートされています。

  • 変数定義。

GraphQLを使用して二面性ビューを定義すると、SQLを使用して定義するよりも利点があります。これについては、「GraphQLを使用したカーレース二面性ビューの作成」で説明します。要約すると、GraphQL構文はより単純で冗長性が低くなります。JSON生成副問合せの結果間の明示的な結合を使用して、サポートされているドキュメントとその部分の形式を記述する必要があると、煩雑でエラーが発生しやすくなります。

Oracle GraphQLの二面性ビューのサポートには、次の構文拡張および簡略化が含まれています:

  1. スカラー型

    Oracle Databaseでは、Oracle JSON言語のスカラー型およびSQLのスカラー型に対応する追加のGraphQLスカラー型がサポートされています。「Oracle GraphQLスカラー型」を参照してください。

  2. 暗黙的なGraphQLフィールド別名

    二面性ビュー定義で使用される別名未指定のGraphQLフィールド名は、実際のGraphQLフィールド名の別名として自動的に取得されます。実際に、これは、二面性ビューでサポートされるドキュメントのフィールド名に対応する、大文字と小文字を区別する照合を行うための簡潔な方法です。「暗黙的なGraphQLフィールド別名」を参照してください。

  3. すべてのスカラー・フィールドのワイルドカード(*)

    二面性ビュー定義では、特定のGraphQL型の各スカラー・フィールドを明示的にリストするかわりに、アスタリスクのワイルドカード*を使用できます。

    *をディレクティブ@upperとともに使用すると、フィールド名が引用符で囲まれていない場合、大文字の別名で暗黙的に指定されます。

    *をディレクティブ@excludeとともに使用すると、引数fieldsで指定されたフィールド以外のすべてのフィールドを含めることができます。

    「スカラーGraphQLフィールドのワイルドカード(*)」を参照してください。

  4. 二面性ビュー用GraphQLディレクティブ

    @upperおよび@exclude (スカラーGraphQLフィールドのワイルドカード(*)を参照)に加えて、Oracle GraphQLには、二面性ビューの定義時に特定の処理を指定する他のディレクティブ(@link@[un]nestおよび@flex)が用意されています。「JSONリレーショナル二面性ビュー用のOracle GraphQLディレクティブ」を参照してください。

  5. 二面性ビュー定義のGraphQL名

    二面性ビュー定義で使用する表および列の名前が標準のGraphQLフィールド名として直接使用できる場合は、そのまま使用されます。たとえば、カーレースの二面性ビューの場合です。

    一般的に、二面性ビュー定義では、(1) JSONフィールド名、(2) GraphQL型とフィールド名、(3) SQL表と列名の間のマッピングを指定します。最初の2つは大/小文字が区別されますが、引用符なしのSQL名は大/小文字が区別されません。また、名前で許可される文字は、GraphQLとSQLで異なります。

    このような理由から、Oracleは、二面性ビュー定義で許可される引用符なしのGraphQL名を緩和および拡張します。

    「GraphQL二面性ビュー定義で使用される名前」を参照してください。

Oracle GraphQLスカラー型

表7-1に、Oracle JSONスカラー型およびOracle SQLスカラー型に対応する、OracleでサポートされているGraphQLスカラー型を示します。標準のGraphQL型とカスタムのOracle固有のGraphQL型の両方がリストされます。

表7-1 スカラー型: Oracle JSON、GraphQLおよびSQL

Oracle JSON言語スカラー型 GraphQLスカラー型 SQLスカラー型

binary

Binary (Oracle固有)

RAWまたはBINARY

date

Date (Oracle固有)

DATE

timestamp

Timestamp (Oracle固有)

TIMESTAMP

timestamp with time zone

TimestampWithTimezone (Oracle固有)

TIMESTAMPWITHTIMEZONE

year-month interval

YearmonthInterval (Oracle固有)

INTERVALYEARTOMONTH

day-second interval

DaysecondInterval (Oracle固有)

INTERVALDAYTOSECOND

double

Float (標準GraphQL)

BINARY_DOUBLE

float

Float (標準GraphQL)

BINARY_FLOAT

暗黙的なGraphQLフィールド別名

二面性ビュー定義の本体は、GraphQL問合せです。フィールド名が別名なしでその問合せで使用されている場合、対応するGraphQLフィールド名を選択するために、大/小文字を区別しないで照合されます。標準のGraphQL問合せでは、このような照合で大/小文字が区別されます。

この便利な機能によって、基本的に、別名のないフィールドには、ビュー定義で使用されている大/小文字で別名が付けられます。別名は、サポートされているドキュメントで使用されるJSONフィールド名に直接対応します。実際のGraphQLフィールド名は、SQL表または列名から導出されます:

たとえば、GraphQLフィールド名がmyfield (小文字)として定義され、二面性ビューの作成問合せでmyFieldを使用する場合、問合せ対象フィールドはmyField : myfieldと記述されているように暗黙的に処理され、ビューでサポートされているJSONドキュメントにはmyFieldというJSONフィールドが含まれています。

スカラーGraphQLフィールドのワイルドカード(*)

アスタリスクのワイルドカード*を使用することは、特定のGraphQL型の各スカラー・フィールドを明示的にリストするのではない、代替の簡単な方法です。ディレクティブ@upperとともに使用すると、引用符なしのフィールド名は大文字の別名で暗黙的に指定されます。

*を使用する場合、対象となるスカラー・フィールドには別名を指定できません。

例2-10では、tableチームのすべての列が、二面性ビューteam_dvの作成に使用されます:

CREATE JSON RELATIONAL DUALITY VIEW team_dv AS
  team
    {teamId : team_id,
     name   : name,
     points : points,
     driver : ...}

これらのスカラー・フィールド(列)、team_idnameおよびpointsに別名が使用されていない場合は、個別にリストするかわりに、ワイルドカード*を使用できます。

次の定義はすべて同等です。(3番目の例では、別名は冗長で、GraphQL型名と同じであり、表teamの列名と同じです。)

CREATE JSON RELATIONAL DUALITY VIEW team_dv AS
  team
    {*,
     driver : ...}
CREATE JSON RELATIONAL DUALITY VIEW team_dv AS
  team
    {team_id,
     name,
     points,
     driver : ...}
CREATE JSON RELATIONAL DUALITY VIEW team_dv AS
  team
    {team_id : team_id,
     name    : name,
     points  : points,
     driver  : ...}

ディレクティブ@upperをワイルドカード*とともに使用すると、すべての大文字のフィールド名のセットを表すことができます。次の定義は同等です:

CREATE JSON RELATIONAL DUALITY VIEW team_dv AS
  team
    {* @upper,
     driver : ...}
CREATE JSON RELATIONAL DUALITY VIEW team_dv AS
  team
    {TEAM_ID : team_id,
     NAME    : name,
     POINTS  : points,
     driver  : ...}

また、ディレクティブ@excludeをワイルドカード*とともに使用すると、引数fieldsで指定されたフィールド以外のすべてのフィールドを取得できます。(除外するフィールドのリストに主キー・フィールドを含めることはできません。除外するとエラーが発生します。)

たとえば、次は同等です(例2-12の定義とは異なり、フィールド名として、raceIdではなくrace_idを使用し、フィールドdateおよびpodiumを排除します):

CREATE JSON RELATIONAL DUALITY VIEW race_dv AS
race
  {raceId : race_id,
   name   : name,
   laps   : laps,
   date   : race_date,
   podium : podium,
   result : ...}
CREATE JSON RELATIONAL DUALITY VIEW race_dv AS
race
  {raceId : race_id,
   date   : race_date,
   * @exclude (fields : ["laps" "podium"],
   result : ...}

GraphQL二面性ビュー定義で使用される名前

Oracleは、二面性ビュー定義で許可される引用符なしのGraphQL名を緩和および拡張します。これは、(1)二面性ビューでサポートされるJSONドキュメントのフィールド名の指定、(2) GraphQL名でのSQL識別子構文(表および列に使用)の使用を容易にするために行われます。

GraphQL二面性ビュー定義で使用する名前のnoneにピリオド(ドット)文字(.)が含まれているか、引用符で囲む必要がある場合、対応するGraphQLスキーマはGraphQL標準に完全に準拠しています。この場合、既存のすべてのGraphQLツールと連携する必要があります。

それ以外の場合(より一般的な場合)、完全準拠ではありません。JSONリレーショナル二面性ビューの作成に使用できますが、一部のGraphQLツールでは正しく動作しない可能性があります。

標準GraphQL名は、次の方法で制限されます:

  • 英数字のASCII文字とアンダースコア(_)文字のみを含めることができます。

  • 2つのアンダースコア文字(__)で始めることはできません。

SQL名に引用符を付けると、二重引用符(") (引用符、コード・ポイント34とも呼ばれる)とnull (コード・ポイント0)を除く任意の文字を含めることができます。引用符なしのSQL名には、英数字(ASCIIまたはこれ以外)、アンダースコア(_)、番号記号(#)、ドル記号($)を使用できます。完全修飾の表名にはピリオド(ドット)文字(.)が含まれ、データベース・スキーマ(ユーザー)名と表名を区切ります。

二面性ビュー定義で許可されるGraphQL名には、次のルールが適用されます。これらのルールの末尾は、完全修飾SQL表名、つまり、データベース・スキーマ(ユーザー)名、ピリオド(ドット)文字(.)およびデータベース表名の3つの部分で構成される<schema name>.<table name>という形式の名前に適用されます。その他のルールは、ドットを含まないSQL名に適用されます。

  • 引用符で囲まれたSQL名(識別子)に対応するGraphQL名は、同じ引用符で囲まれた名前です。

    たとえば、"this name"はSQLとGraphQLで同じです。

  • ASCII英数字またはアンダースコア(_)文字のみで構成される引用符なしのSQL名に対応するGraphQL名は、次の点を除いてSQL名と同じです:

    • GraphQL フィールド名は小文字です。

      たとえば、GraphQLフィールド名MY_NAMEは、SQL名my_nameに対応します。

    • GraphQL名の最初の文字は大文字です。

      たとえば、GraphQL型名My_nameは、SQL名MY_NAMEに対応します。

  • 非ASCII英数字番号記号(#)、またはドル記号($)文字を1つ以上含む引用符なしのSQL名に対応するGraphQL名は同じ名前ですが、大文字で引用符付きです。(Oracle SQLでは、このような名前は引用符で囲まれているかどうかに関係なく、大/小文字が区別されません。)

    たとえば、GraphQL名"MY#NAME$4"は、SQL名my#name$4に対応します

  • 完全修飾SQL表名に対応するGraphQL名は、形式が<schema name>.<table name>で、(1) <schema name>に対応するGraphQL名と、(2)ピリオド(ドット)文字(.)と、(3) <table name>に対応するGraphQL名を連結したものです。GraphQL名では、ドットが引用符で囲まれていないことに注意してください。

    完全修飾SQL名の例:

    • GraphQL名My_schema.Mytableは、SQL名MY_SCHEMA.MYTABLEに対応します。

    • GraphQL名"mySchema".Mytableは、SQL名"mySchema".mytableに対応します。

    • GraphQL名"mySchema"."my table"は、SQL名"mySchema"."my table"に対応します。

    • GraphQL名"Schema#3.Table$4"は、SQL名SCHEMA#3.TABLE$4に対応します。

関連項目:

Graph QL

7.1 JSONリレーショナル二面性ビュー用のOracle GraphQLディレクティブ

GraphQLディレクティブは、GraphQLスキーマの追加情報または特定の動作を指定する注釈です。二面性ビューを定義するためのすべてのOracle GraphQLディレクティブは、GraphQLフィールドに適用されます。

ディレクティブは、接頭辞@が付いた名前で、場合によっては引数が続きます。

二面性ビューを定義するためのOracle GraphQLには、次のディレクティブがあります:

  • ディレクティブ@flexは、JSON型の列を二面性ビュー用のフレックス列として指定します。このディレクティブの使用については、「フレックス列: 二面性ビューのスキーマの柔軟性と展開」を参照してください。

  • ディレクティブ@nestおよび@unnestは、二面性ビュー定義の中間オブジェクトのネストおよびネスト解除(フラット化)を指定します。これらは、それぞれSQLキーワードNESTおよびUNNESTに対応します。

    デフォルトでは、ルート表列に対応するフィールドはネストされず、ルート以外の表の列に対応するフィールドはネストされます。ルート表の主キー列に対応するフィールドはネストできません。ネストしようとするとエラーが発生します。

    例7-1に、@nestの使用例を示します。@unnestを使用する例については、「GraphQLを使用したカーレース二面性ビューの作成」を参照してください。

  • @upperおよび@excludeディレクティブは、GraphQL型のスカラー・フィールドを指定する場合のアスタリスク(*)ワイルドカードの動作を修飾します。これらは、「スカラーGraphQLフィールドのワイルドカード(*)」で説明されています。

  • ディレクティブ@linkは、列間の複数の外部キー・リンクを区別します。「Oracle GraphQLディレクティブ@link」を参照してください。

  • ディレクティブ@[no]update@[no]insertおよび@[no]deleteは、注釈を更新する二面性ビューとして機能します。これらは、SQL注釈キーワード[NO]UPDATE、[NO]INSERTおよび[NO]DELETEに対応しており、「注釈(NO)UPDATE、(NO)INSERT、(NO)DELETEによる更新操作の許可/禁止」で説明されています。

  • ディレクティブ@[no]checkは、オプティミスティックな同時実行性制御に対応する二面性ビューの部分を決定します。これらは、SQL注釈キーワード[NO]CHECKに対応しています。詳細は、「GraphQLを使用したカーレース二面性ビューの作成」を参照してください。

例7-1 ネストされたドライバ情報を使用した二面性ビューDRIVER_DV1の作成

この例では、二面性ビューdriver_dv1を作成しています。これは、例2-11でGraphQLを使用して定義され、例2-7でSQLを使用して定義されたビューdriver_dvと同じです。ただし、表driverの列のフィールドnameおよびpointsは、フィールドdriverInfoの値であるサブオブジェクトでネストされます。脚注1フィールドdriverInfoの指定は、ビューdriver_dv1の定義と元のビューdriver_dvの定義の違いのみです。

driver_dv1の対応するGraphQL定義およびSQL定義を示します。

CREATE JSON RELATIONAL DUALITY VIEW driver_dv1 AS
  driver
    {_id       : driver_id,
     driverInfo : driver @nest {name   : name,
                                points : points},
     name      : name,
     points    : points,
     team @unnest {teamId : team_id,
                   name   : name},
     race      : driver_race_map
                  [ {driverRaceMapId : driver_race_map_id,
                     race @unnest {raceId : race_id,
                                   name   : name},
                     finalPosition : position} ]};

次に対応するSQL定義を示します:

CREATE JSON RELATIONAL DUALITY VIEW driver_dv1 AS
  SELECT JSON {'_id'        : d.driver_id,
               'driverInfo' : {'name'   : d.name,
                               'points' : d.points},
               UNNEST
                 (SELECT JSON {'teamId' : t.team_id,
                               'team'   : t.name}
                    FROM team t
                    WHERE t.team_id = d.team_id),
               'race'     :
                 [ SELECT JSON {'driverRaceMapId' : drm.driver_race_map_id,
                                UNNEST
                                  (SELECT JSON {'raceId' : r.race_id,
                                                'name'   : r.name}
                                     FROM race r
                                     WHERE r.race_id = drm.race_id),
                                'finalPosition'   : drm.position}
                    FROM driver_race_map drm
                    WHERE drm.driver_id = d.driver_id ]}
    FROM driver d;

driverはビューのルート表であるため、デフォルトでフィールドはすべてビューにネストされず、GraphQLで@nestを使用してネストする必要があります。

(ルート以外の表のフィールドはデフォルトでネストされており、ネストを解除するには@unnest (SQLではキーワードUNNEST)を明示的に使用する必要があります。これは、チーム・フィールドteamIdname、およびレース・フィールドraceIdnameの場合です。)

7.1.1 Oracle GraphQLディレクティブ@link

GraphQLディレクティブ@linkは、列間の複数の外部キー・リンクを区別します。

ディレクティブ@linkは、外部キー列と主キー列または一意キー列の間のリンクを、二面性ビューの基礎となる表で指定します。通常、列は別の表のためのものですが、同じ表の列もリンクできます。この場合、外部キーは自己参照と呼ばれます。

一般に、外部キー・リンクを明示的に指定する必要がないという点は、二面性ビュー定義に対してGraphQLが示す、SQLより優れている利点です。このようなリンクは通常、基礎となる表依存関係グラフによって推測されるため、冗長性が低くなります。

GraphQLで外部キー・リンクを明示的に使用する必要があるのは、2つの表の間に複数の外部キー関係がある場合、または表に同じ表を参照する外部キーがある場合のみです。このような場合は、@linkディレクティブを使用して、特定のリンク(外部キーと方向)を指定します。

例7-2team_w_lead表定義には、列lead_driverからdriver表の列driver_idへの外部キー・リンクがあります。また、driver表には、列team_idからteam_w_lead表の主キー列team_idへの外部キー・リンクがあります。

図7-1の表依存関係グラフは、これら2つの依存関係を示しています。これは図2-3のグラフと同じですが、表team_w_leadの外部キー列lead_driverから表driverの主キー列driver_idへの追加リンクが含まれている点が異なります。

対応するチームの二面性ビューの定義は、例7-3および例7-4にあります。

図7-1 チーム・リーダーがいるカーレースの例、表依存関係グラフ

図7-1の説明を次に示します
「図7-1 チーム・リーダーがいるチーム・カーレースの例、表依存関係グラフ」の説明

@linkディレクティブには、toまたはfromという名前の単一の引数が必要です。この引数では、値がネストされたオブジェクトである二面性ビュー・フィールドに対して、(1)ネストされたオブジェクトのフィールドを定義する列を持つ表の外部キー(to方向)を使用するか、(2)列がオブジェクトのフィールドのネスト/囲みを使用するかを定義する列を持つ表の外部キーを使用するか(from方向)を指定します。

toまたはfrom引数の値は文字列のGraphQLリストで、各文字列は単一の外部キー列(たとえば、to : ["fkcol"])を指定します。複数の文字列のGraphQLリストは、複合外部キー(to : ["fkcol1", "fkcol2"]など)を表します。(GraphQLリストは、JSON配列に対応しています。カンマは、GraphQLではオプションです。)

例7-2 LEAD_DRIVER列を使用した表TEAM_W_LEADの作成

この例では、表team_w_leadを作成します。これは、例2-4の表teamと同じです。ただし、表driverの列driver_idへの外部キーである追加の列lead_driverがある点が異なっています。

CREATE TABLE team_w_lead
  (team_id     INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
   name        VARCHAR2(255) NOT NULL UNIQUE,
   lead_driver INTEGER,
   points      INTEGER NOT NULL,
   CONSTRAINT team_pk PRIMARY KEY(team_id)
   CONSTRAINT lead_fk FOREIGN KEY lead_driver REFERENCES driver(driver_id));

また、表driverには、表team_w_leadの列team_idを参照する外部キー列team_idがあります。表team_w_leaddriverの間に2つの外部キー・リンクがあるため、これらの表を使用するチームおよびドライバの二面性ビューでは、例7-3および例7-4に示すように、ディレクティブ@linkを使用する必要があります。

例7-3 GraphQLディレクティブ@linkを示す、LEAD_DRIVERを使用した二面性ビューTEAM_DV2の作成

この例は例2-10と似ていますが、例7-2で定義されている表team_w_leadを使用しており、これには外部キー列lead_driverがあります。表team_w_leaddriverの間に2つの外部キー関係があるため、ディレクティブ@linkを使用して、使用する外部キーとその場所を指定する必要があります。

最上位レベルのJSONフィールドleadDriverの値は、表team_w_leadの外部キー列lead_driverによって提供されるドライバ・オブジェクトです。最上位フィールドdriverの値は、表driverの外部キー列team_idによって提供されるドライバ・オブジェクトのJSON配列です。

フィールドleadDriver@link引数は、fromを使用します。その値lead_driverが、外部にある/ネストするオブジェクトの基礎となる表team_w_leadの外部キー列であるためです。

フィールドdriver@link引数はtoを使用します。その値team_idが、内部にある/ネストされるオブジェクトの基礎となる表driverの外部キー列であるためです。

CREATE JSON RELATIONAL DUALITY VIEW team_dv2 AS
  team_w_lead
    {_id        : team_id,
     name       : name,
     points     : points,
     leadDriver : driver @link (from : ["lead_driver"])
       {driverId : driver_id,
        name     : name,
        points   : points},
     driver     : driver @link (to : ["team_id"]) 
       [ {driverId : driver_id,
          name     : name,
          points   : points} ]};

例7-4 GraphQLディレクティブ@linkを示す、二面性ビューDRIVER_DV2の作成

この例は例2-11と似ていますが、例7-2で定義されている表team_w_leadを使用しており、これには外部キー列lead_driverがあります。表team_w_leaddriverの間に2つの外部キー関係があるため、ディレクティブ@linkを使用して、使用する外部キーとその場所を指定する必要があります。

フィールドteam@link引数はfromを使用します。その値team_idが、外部にある/ネストするオブジェクトの基礎となる表driverの外部キー列であるためです。

CREATE JSON RELATIONAL DUALITY VIEW driver_dv2 AS
  driver
    {_id       : driver_id
     name      : name
     points    : points
     team      : team_w_lead
       @link (from: ["team_id"])
       @unnest
       {teamId : team_id,
        name   : name}
     race      : driver_race_map
                   [ {driverRaceMapId : driver_race_map_id,
                      race @unnest
                        {raceId       : race_id,
                         name         : name}
                      finalPosition   : position} ]};


脚注一覧

脚注1: 注釈の更新およびETAGチェックはここには表示されません。