3 更新可能なJSONリレーショナル二面性ビュー

ビューを更新可能として定義すると、アプリケーションでは二面性ビューでサポートされているJSONドキュメントを更新できます。どの種類の更新操作(更新、挿入、削除)を許可するか、どのドキュメント・フィールドを誰がいつどのように更新するかを指定できます。また、ETAGハッシュ値に関与するフィールドも指定できます。

二面性ビュー自体はデータを格納しません。サポートされているJSONドキュメント(生成される)の基礎となるデータはすべて、ビューの基礎となる表に格納されます。ただし、多くの場合、その表データはビューに格納されていると考えると便利です。同様に、二面性ビューが更新可能であるということは、表の一部または全部のデータを更新でき、そのためサポートされているドキュメント内のフィールドの一部または全部を更新できるということを意味します。

アプリケーションは、既存のドキュメントを置換して完全なドキュメントを更新できます。または、特定のフィールドのみを更新することもできます。

アプリケーションでは、ドキュメントが以前の状態から変更されていない(たとえば、データベースから最後に取得されてから変更されていない)場合にのみ、オプションでドキュメントに対して更新を実行できます。

アプリケーションでは、オプションで、データベース・トリガーを使用して、更新後に一部のアクションを自動的に実行することもできます。

3.1 注釈(NO)UPDATE、(NO)INSERT、(NO)DELETEによる更新操作の許可/禁止

キーワードUPDATEは、注釈付きデータを更新できることを意味します。キーワードINSERTおよびDELETEは、注釈で対応されたフィールド/列をそれぞれ挿入または削除できることを意味します。

二面性ビューのデータで、様々な更新操作(挿入、削除、更新)を許可できます。表および列の注釈を使用して、ビューの作成時に許可される操作を指定します。許可される操作は、次のように、ルート表と他の表またはその列の注釈に基づいています。

  • 二面性ビューのデータは、ルート表にキーワードINSERTまたはDELETEで注釈付けされている場合、挿入可能または更新可能です。

  • 二面性ビューは、定義で使用されている表または列にキーワードUPDATEの注釈が付けられている場合、更新可能です。

デフォルトでは、二面性ビューは読取り専用です。二面性ビューの定義に使用される表データはビューから変更できません。これは、デフォルトで、二面性ビュー自体のデータが挿入可能、削除可能、更新可能でないことを意味します。したがって、キーワードNOUPDATENOINSERTおよびNODELETEは、二面性ビューを定義するすべてのFROM句にデフォルトで関連しています。

特定のFROM句のレベルの更新可能性を指定するには、キーワードWITHに続けて、(NO)UPDATE、(NO)INSERTおよび(NO)DELETEの1つ以上のキーワードを指定します。表レベルの更新性は、同じFROM句によって制御されるすべての列のうち、列レベル(NO)UPDATE注釈を上書きするものをを除く列を定義します。(列レベルが表レベルよりも優先されます。)

二面性ビューのレベルの部分(JSONドキュメント・フィールドに対応)が更新可能であることを指定するには、フィールド列(キー値)の指定後に注釈WITHを使用し、その後にキーワードUPDATEまたはNOUPDATEを付けます。たとえば、'name' : r.name WITH UPDATEは、table rNOUPDATEを指定して宣言されている場合でも、フィールドnameおよび列r.nameが更新可能であることを指定します。

たとえば、例2-6および例2-7では、次のようになります:

  • teamのフィールド/列(チーム・フィールド_idおよびname)は挿入、削除または更新できません(WITH NOINSERT NOUPDATE NODELETE)。したがって、同様に、表raceのフィールド/列(レース・フィールド_idおよびname)の場合は、raceInfoも挿入、削除または更新できません。

  • マッピング表driver_race_mapのすべてのフィールド/列(フィールド_idおよびfinalPosition)は挿入および更新できますが、削除できません(WITH INSERT UPDATE NODELETE)。

  • driverのすべてのフィールド/列(ドライバ・フィールド_idnameおよびpoints)は、挿入、更新および削除できます(WITH INSERT UPDATE DELETE)。

二面性ビューdriver_dvおよびteam_dvでは、表レベルの更新可能性の注釈のみがあります(列レベルの注釈はありません)。ただし、ビューrace_dvでは、フィールドlaps (表raceの列laps)に注釈WITH NOUPDATEがあり、表raceの列に対する表レベルの更新許可をオーバーライドします。特定のレースに定義されたラップ数は変更できません。

3.2 注釈(NO)CHECKによるETAG計算のフィールドの包含/除外

更新操作の実行時にドキュメントの状態/バージョンのチェックに使用するドキュメントの部分を宣言的に指定するには、このようなドキュメントをサポートする二面性ビューの定義に注釈を付けます。

アプリケーションがドキュメントを更新するときに、更新するドキュメントのバージョン/状態が、ドキュメントが最後にデータベースから取得されてから変更されていないことを確認する必要があります。

これを実装する方法の1つは、ロックフリーであるオプティミスティックな同時実行性制御を使用することです。デフォルトでは、二面性ビューでサポートされるドキュメントはすべて、ETAGフィールドetagの形式でドキュメント状態の署名を記録します。フィールド値は、ドキュメント・コンテンツやその他の情報のハッシュ値として構築され、ドキュメントが取得されるたびに自動的に更新されます。

ローカルで更新したドキュメントがアプリケーションによって書き込まれると、データベースは格納されたドキュメントの現在の状態について最新のETAG値を自動的に計算し、更新対象の(アプリケーションによって送信された)ドキュメントに埋め込まれたetag値に対してこの値をチェックします。

2つの値が一致しない場合、更新操作は失敗します。その場合、アプリケーションは、データベースから最新バージョンのドキュメントを取得し、(フィールドetagの新しい値を変更せずに)更新の必要に応じて変更し、(新たに変更された)ドキュメントの書込みを再試行できます。「二面性ビューでのオプティミスティックな同時実行性制御の使用」を参照してください。

デフォルトでは、ドキュメントのすべてのフィールドは、フィールドetagの値の計算に関与します。特定のフィールドがこの計算に関与しないように除外するには、その列にキーワードNOCHECKを付けます(更新可能性の注釈と同様に、WITHの後に続けます)。更新可能性の注釈と同様に、FROM句にNOCHECKを指定して、その句の影響を受けるすべての列に適用できます。その場合、CHECKを使用して特定の列に注釈を付け、表レベルのNOCHECKの影響から除外できます。

更新操作が成功すると、ETAG計算に関与しないフィールドの変更を含め、定義されている変更はすべて行われるため、その間に加えられた可能性があるそのフィールドの変更は上書きされます。つまり、ETAG計算に含まれないフィールドは、更新操作で無視されません

たとえば、ビューdriver_dvのフィールドteamはドライバのチーム情報を含むオブジェクトであり、このチーム・オブジェクトのフィールドnameには例2-7NOCHECKという注釈が付けられています。つまり、チーム名はドライバ・ドキュメントのETAG値の計算に関与しません

チーム名はドライバドキュメントのETAG計算に関与しないため、そのドキュメント内のチーム情報に対する変更は考慮されません。表teamはビューdriver_dvの定義でNOUPDATEとマークされているため、ドライバ・ドキュメントの更新時にそのチーム情報が無視されても問題はありません。

しかしながら、表teamが、そうではなくUPDATEとマークされていたらどうでしょうか。その場合は、ドライバ・ドキュメントを更新すると、ドライバのチーム情報が更新される可能性があります。これは、表team内のデータが変更されるということです。

アプリケーションでそのドライバのドキュメントが最後に読み取られてから、ドライバのチーム情報が外部でなんらかの形で変更されたとします。たとえば、チームの名前が"OLD Team Name"から"NEW Team Name"に変更された場合です。

その後、そのドライバ・ドキュメントを更新しても、チーム名の競合により失敗することはありません (別の理由で失敗する可能性はあります)。"NEW Team Name"に対する以前の変更は、無視されるだけです。そのチーム名は、ドライバドキュメント更新操作で指定されたname値("OLD Team Name"など)で上書きされます。

更新操作で指定したドキュメントまたはドキュメント・フラグメントからチームのname省くだけで、この問題を回避できます(この問題は表teamをドライバ・ドキュメントを介して更新できる場合のみ発生する可能性があります)。

同様に、チーム・ドキュメントのフィールドdriverはドライバ・オブジェクトの配列であり、それらのオブジェクトのフィールドpointsにはNOCHECKという注釈が付けられます(例2-5を参照)。したがって、(アプリケーションの)別のセッションによるそのフィールドへの変更はチーム・ドキュメントの更新を妨げません。(更新操作で無視されない、ETAG計算に含まれないフィールドについての注意事項は、ここでも当てはまります。)

全体としての二面性ビューでは、実際、列にNOCHECKの注釈が付けられていない場合、そのドキュメントはETAGがチェックされています。すべての列がNOCHECKの場合、ドキュメント・フィールドはETAGの計算に関与しません。これにより、パフォーマンスが向上し、大規模ドキュメントではさらに向上します。二面性ビューをすべてのETAGチェックから除外する場合のユースケースには、次のものがあります。

  • アプリケーションでは独自の方法で同時実行性を制御できるため、データベースのETAGチェックは必要ありません。

  • アプリケーションは単一スレッドであるため、同時に変更することはできません。

PL/SQLファンクションDBMS_JSON_SCHEMA.describeを使用して、二面性ビューにETAGチェック済のドキュメントがあるかどうかを確認できます。その場合、上位レベルの配列フィールドpropertiesには要素"check"が含まれています。

3.3 二面性ビューの更新操作に必要なデータベース権限

アプリケーションが特定の二面性ビューのデータに対して実行できる操作の種類は、ビュー所有者と、アプリケーションがデータベースに接続する際に使用するデータベース・ユーザー(データベース・スキーマ)に付与されたデータベース権限によって異なります。

これにより、関連する権限をユーザーに付与することで、どのアプリケーション/ユーザーがどの二面性ビューでどのアクションを実行できるかを制御できます。

アプリケーションは、特定のデータベース・ユーザーとしてデータベース操作を起動します。ただし、二面性ビューでの更新操作(挿入と削除を含む)は、ビューの所有者として実行されます。

二面性ビューのデータに対して様々な種類の操作を実行するには、ユーザー(またはユーザーとして接続されているアプリケーション)にビューに対する次の権限を付与する必要があります。

  • データを問い合せるには: 権限SELECT WITH GRANT OPTION

  • ドキュメント(行)を挿入するには: 権限INSERT WITH GRANT OPTION

  • ドキュメント(行)を削除するには: 権限DELETE WITH GRANT OPTION

  • ドキュメント(行)を更新するには: 権限UPDATE WITH GRANT OPTION

また、ビューの所有者は、関連する各のそれぞれに対して、つまり、対応するキーワードで注釈付けされたすべての表に対して、同じ権限が必要です。たとえば、挿入の場合、ビュー所有者は、INSERTを使用してビュー定義で注釈が付けられているすべての表に対する権限INSERT WITH GRANT OPTIONが必要です。

二面性ビューに対して操作が実行されると、ビューにアクセスして操作を要求しているユーザーまたはアプリケーションに関係なく、ビューの基礎となる表に必要な操作がビュー所有者として実行されます。このため、ビューにアクセスするユーザー自身には、基礎となる表に対する権限が不要です。

ルール1の更新に関する項も参照してください。

3.4 二面性ビューを更新するためのルール

二面性ビューでサポートされるドキュメントを更新する場合は、一部のルールを考慮する必要があります。

  1. ドキュメント更新操作(更新、挿入または削除)が試行され、現在のユーザーまたはビュー所有者に必要な権限が付与されていない場合、試行時にエラーが発生します。(関連する権限については、「二面性ビューの更新操作に必要なデータベース権限」を参照してください。)

  2. 試行されたドキュメント更新操作(更新、挿入または削除)が二面性ビューの基礎となる表に適用されている制約に違反した場合、エラーが発生します。これには、主キー、一意キー、NOT NULLの参照整合性およびチェック制約が含まれています。

  3. ドキュメント更新操作(更新、挿入または削除)が試行され、その操作がビューの注釈で考慮されていない場合は、試行時にエラーが発生します。

  4. ドキュメントを二面性ビューに挿入する場合、ドキュメントには、(1)ドキュメントのETAG値に関与し、かつ(2)ビュー定義で更新専用または読取り専用とマークされた(ルート以外の)表の列に対応するすべてのフィールドが含まれている必要があります。また、対応する列データが表にすでに存在している必要があります。これらの条件が満たされない場合は、エラーが発生します。

    読取り専用列に対応するすべてのフィールドの値も、表内の対応する列値と一致する必要があります。そうでない場合は、エラーが発生します。

    たとえば、二面性ビューrace_dvdriver表を使用すると、更新専用(WITH NOINSERT UPDATE NODELETEの注釈付き)になります。新しいレース・ドキュメントを挿入する場合、ドキュメントにはdriver表の列driver_idおよびnameに対応するフィールドが含まれている必要があり、driver表には、そのドキュメントのドライバ情報に対応するデータがすでに含まれている必要があります。

    同様に、driver表がビューrace_dvで(更新専用ではなく)読取り専用とマークされている場合、入力ドキュメントのドライバ情報は表の既存のデータと同じである必要があります。

  5. 1対多で主キーと外部キーの関係で親にリンクされているオブジェクトを削除する場合、オブジェクトに注釈DELETEがないと、そのオブジェクトはカスケード削除されません。かわりに、オブジェクトの各行の外部キーはNULLに設定されます(外部キーにNULL値不可の制約がないとします)。

    たとえば、ビューteam_dvdriver配列はNODELETEです(DELETEに注釈が付けられていないため、暗黙的)。ビューteam_dvからチームを削除すると、対応する行が表teamから削除されます。

    ただし、driver表の対応する行は削除されません。かわりに、これらの各行は、外部キー列team_idの値をSQL NULLに設定することで、削除されたチームからリンク解除されます。

    同様に、ドライバのドキュメントは削除されません。ただし、チーム情報は削除されます。例2-6のバージョンでは、フィールドteamInfoの値が空のオブジェクト({})に設定されています。例2-7のバージョンでは、チーム・フィールドのteamIdおよびteamはそれぞれJSON nullに設定されています。

    二面性ビューteam_dvの定義での表driverの使用に注釈DELETEがあり、削除を許可するとどうなるのでしょうか。この場合、特定のチームを削除すると、ドライバもすべて削除されます。これは、driver表からこれらの行が削除され、対応するすべてのドライバ・ドキュメントも削除されることを意味します。

  6. 完全なドキュメントを置き換える更新操作では、ETAG値に関与するものとしてビューによって定義されたすべてのフィールド(つまり、注釈CHECKが適用されるすべてのフィールド)が新しい(置換)ドキュメントに含まれている必要があります。そうでない場合は、エラーが発生します。

    このルールは、演算子KEEPまたはREMOVEを使用する場合のOracle SQLファンクションjson_transformの使用にも適用されます。ETAG値に関与するフィールドがドキュメントから削除されると、エラーが発生します。

  7. 二面性ビューに同じビューの主キーまたは一意キーを参照する外部キーを持つ基礎となる表がある場合、ドキュメント更新操作(更新、挿入または削除)では、その主キーまたは一意キーの値を変更できません。これを試行すると、エラーが発生します。

  8. ドキュメント更新操作(更新、挿入または削除)に基礎となる表の同じ行の更新が含まれる場合、その行の内容は2つの異なる方法で変更することはできません。そうでない場合は、エラーが発生します。

    たとえば、driver表の同じ行(主キーdriver_id値が105の行)のドライバname"George Russell""Lewis Hamilton"の両方にすることはできないため、この挿入の試行は失敗します。

    INSERT INTO team_dv VALUES
      ('{"_id"   : 303,
         "name"   : "Mercedes",
         "points" : 0,
         "driver" : [ {"driverId" : 105,
                       "name"     : "George Russell",
                       "points"   : 0},
                      {"driverId" : 105,
                       "name"     : "Lewis Hamilton",
                       "points"   : 0} ]}');
  9. 更新操作(更新、挿入または削除)のために送信されるドキュメントに埋め込まれたetagフィールド値が現在のデータベース状態と一致しない場合は、エラーが発生します。

  10. ドキュメント更新操作(更新、挿入または削除)が、同じ二面性ビューでサポートされる2つ以上のドキュメントに影響する場合は、基礎となる表の特定の行のデータに対するすべての変更に互換性がある(一致している)必要があります。そうでない場合は、エラーが発生します。たとえば、ドライバごとに、この操作は最初のレースの名前($.race[0].name)をドライバの名前($.name)に設定しようとします。

    UPDATE driver_dv
      SET data = json_transform(data,
                                SET '$.race[0].name' =
                                json_value(data, '$.name'));
    ERROR at line 1:ORA-42605:
    Cannot update JSON Relational Duality View 'DRIVER_DV':
    cannot modify the same row of the table 'RACE' more than once.