3 更新可能なJSONリレーショナル二面性ビュー
ビューを更新可能として定義すると、アプリケーションでは二面性ビューでサポートされているJSONドキュメントを更新できます。どの種類の更新操作(更新、挿入、削除)を許可するか、どのドキュメント・フィールドを誰がいつどのように更新するかを指定できます。また、ETAGハッシュ値に関与するフィールドも指定できます。
二面性ビュー自体はデータを格納しません。サポートされているJSONドキュメント(生成される)の基礎となるデータはすべて、ビューの基礎となる表に格納されます。ただし、多くの場合、その表データはビューに格納されていると考えると便利です。同様に、二面性ビューが更新可能であるということは、表の一部または全部のデータを更新でき、そのためサポートされているドキュメント内のフィールドの一部または全部を更新できるということを意味します。
アプリケーションは、既存のドキュメントを置換して完全なドキュメントを更新できます。または、特定のフィールドのみを更新することもできます。
アプリケーションでは、ドキュメントが以前の状態から変更されていない(たとえば、データベースから最後に取得されてから変更されていない)場合にのみ、オプションでドキュメントに対して更新を実行できます。
アプリケーションでは、オプションで、データベース・トリガーを使用して、更新後に一部のアクションを自動的に実行することもできます。
- 注釈(NO)UPDATE、(NO)INSERT、(NO)DELETEによる更新操作の許可/禁止
キーワードUPDATE
は、注釈を付けたデータを更新できるという意味です。キーワードINSERT
およびDELETE
は、注釈で対応されたフィールド/列をそれぞれ挿入または削除できることを意味します。 - 注釈(NO)CHECKによるETAG計算のフィールドの包含/除外
更新操作の実行時にドキュメントの状態/バージョンのチェックに使用するドキュメントの部分を宣言的に指定するには、このようなドキュメントをサポートする二面性ビューの定義に注釈を付けます。 - 二面性ビューの更新操作に必要なデータベース権限
アプリケーションが特定の二面性ビューのデータに対して実行できる操作の種類は、ビュー所有者と、アプリケーションがデータベースに接続する際に使用するデータベース・ユーザー(データベース・スキーマ)に付与されたデータベース権限によって異なります。 - 二面性ビューを更新するためのルール
二面性ビューでサポートされるドキュメントを更新する場合は、一部のルールを考慮する必要があります。
3.1 注釈(NO)UPDATE、(NO)INSERT、(NO)DELETEによる更新操作の許可/禁止
キーワードUPDATE
は、注釈付きデータを更新できることを意味します。キーワードINSERT
およびDELETE
は、注釈で対応されたフィールド/列をそれぞれ挿入または削除できることを意味します。
二面性ビューのデータで、様々な更新操作(挿入、削除、更新)を許可できます。表および列の注釈を使用して、ビューの作成時に許可される操作を指定します。許可される操作は、次のように、ルート表と他の表またはその列の注釈に基づいています。
-
二面性ビューのデータは、ルート表にキーワード
INSERT
またはDELETE
で注釈付けされている場合、挿入可能または更新可能です。 -
二面性ビューは、定義で使用されている表または列にキーワード
UPDATE
の注釈が付けられている場合、更新可能です。
デフォルトでは、二面性ビューは読取り専用です。二面性ビューの定義に使用される表データはビューから変更できません。これは、デフォルトで、二面性ビュー自体のデータが挿入可能、削除可能、更新可能でないことを意味します。したがって、キーワードNOUPDATE
、NOINSERT
およびNODELETE
は、二面性ビューを定義するすべてのFROM
句にデフォルトで関連しています。
特定のFROM
句の表レベルの更新可能性を指定するには、キーワードWITH
に続けて、(NO
)UPDATE
、(NO
)INSERT
および(NO
)DELETE
の1つ以上のキーワードを指定します。表レベルの更新性は、同じFROM
句によって制御されるすべての列のうち、列レベル(NO
)UPDATE
注釈を上書きするものをを除く列を定義します。(列レベルが表レベルよりも優先されます。)
二面性ビューの列レベルの部分(JSONドキュメント・フィールドに対応)が更新可能であることを指定するには、フィールド列(キー値)の指定後に注釈WITH
を使用し、その後にキーワードUPDATE
またはNOUPDATE
を付けます。たとえば、'name' : r.name WITH UPDATE
は、table r
がNOUPDATE
を指定して宣言されている場合でも、フィールドname
および列r.name
が更新可能であることを指定します。
-
表
team
のフィールド/列(チーム・フィールド_id
およびname
)は挿入、削除または更新できません(WITH NOINSERT NOUPDATE NODELETE
)。したがって、同様に、表race
のフィールド/列(レース・フィールド_id
およびname
)の場合は、raceInfo
も挿入、削除または更新できません。 -
マッピング表
driver_race_map
のすべてのフィールド/列(フィールド_id
およびfinalPosition
)は挿入および更新できますが、削除できません(WITH INSERT UPDATE NODELETE
)。 -
表
driver
のすべてのフィールド/列(ドライバ・フィールド_id
、name
およびpoints
)は、挿入、更新および削除できます(WITH INSERT UPDATE DELETE
)。
二面性ビューdriver_dv
およびteam_dv
では、表レベルの更新可能性の注釈のみがあります(列レベルの注釈はありません)。ただし、ビューrace_dv
では、フィールドlaps
(表race
の列laps
)に注釈WITH NOUPDATE
があり、表race
の列に対する表レベルの更新許可をオーバーライドします。特定のレースに定義されたラップ数は変更できません。
親トピック: 更新可能なJSONリレーショナル二面性ビュー
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-7でNOCHECK
という注釈が付けられています。つまり、チーム名はドライバ・ドキュメントの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の更新に関する項も参照してください。
親トピック: 更新可能なJSONリレーショナル二面性ビュー
3.4 二面性ビューを更新するためのルール
二面性ビューでサポートされるドキュメントを更新する場合は、一部のルールを考慮する必要があります。
-
ドキュメント更新操作(更新、挿入または削除)が試行され、現在のユーザーまたはビュー所有者に必要な権限が付与されていない場合、試行時にエラーが発生します。(関連する権限については、「二面性ビューの更新操作に必要なデータベース権限」を参照してください。)
-
試行されたドキュメント更新操作(更新、挿入または削除)が二面性ビューの基礎となる表に適用されている制約に違反した場合、エラーが発生します。これには、主キー、一意キー、
NOT NULL
の参照整合性およびチェック制約が含まれています。 -
ドキュメント更新操作(更新、挿入または削除)が試行され、その操作がビューの注釈で考慮されていない場合は、試行時にエラーが発生します。
-
ドキュメントを二面性ビューに挿入する場合、ドキュメントには、(1)ドキュメントのETAG値に関与し、かつ(2)ビュー定義で更新専用または読取り専用とマークされた(ルート以外の)表の列に対応するすべてのフィールドが含まれている必要があります。また、対応する列データが表にすでに存在している必要があります。これらの条件が満たされない場合は、エラーが発生します。
読取り専用列に対応するすべてのフィールドの値も、表内の対応する列値と一致する必要があります。そうでない場合は、エラーが発生します。
たとえば、二面性ビュー
race_dv
でdriver
表を使用すると、更新専用(WITH NOINSERT UPDATE NODELETE
の注釈付き)になります。新しいレース・ドキュメントを挿入する場合、ドキュメントにはdriver
表の列driver_id
およびname
に対応するフィールドが含まれている必要があり、driver
表には、そのドキュメントのドライバ情報に対応するデータがすでに含まれている必要があります。同様に、
driver
表がビューrace_dv
で(更新専用ではなく)読取り専用とマークされている場合、入力ドキュメントのドライバ情報は表の既存のデータと同じである必要があります。 -
1対多で主キーと外部キーの関係で親にリンクされているオブジェクトを削除する場合、オブジェクトに注釈
DELETE
がないと、そのオブジェクトはカスケード削除されません。かわりに、オブジェクトの各行の外部キーはNULL
に設定されます(外部キーにNULL
値不可の制約がないとします)。たとえば、ビュー
team_dv
のdriver
配列はNODELETE
です(DELETE
に注釈が付けられていないため、暗黙的)。ビューteam_dv
からチームを削除すると、対応する行が表team
から削除されます。ただし、
driver
表の対応する行は削除されません。かわりに、これらの各行は、外部キー列team_id
の値をSQLNULL
に設定することで、削除されたチームからリンク解除されます。同様に、ドライバのドキュメントは削除されません。ただし、チーム情報は削除されます。例2-6のバージョンでは、フィールド
teamInfo
の値が空のオブジェクト({}
)に設定されています。例2-7のバージョンでは、チーム・フィールドのteamId
およびteam
はそれぞれJSONnull
に設定されています。二面性ビュー
team_dv
の定義での表driver
の使用に注釈DELETE
があり、削除を許可するとどうなるのでしょうか。この場合、特定のチームを削除すると、ドライバもすべて削除されます。これは、driver
表からこれらの行が削除され、対応するすべてのドライバ・ドキュメントも削除されることを意味します。 -
完全なドキュメントを置き換える更新操作では、ETAG値に関与するものとしてビューによって定義されたすべてのフィールド(つまり、注釈
CHECK
が適用されるすべてのフィールド)が新しい(置換)ドキュメントに含まれている必要があります。そうでない場合は、エラーが発生します。このルールは、演算子
KEEP
またはREMOVE
を使用する場合のOracle SQLファンクションjson_transform
の使用にも適用されます。ETAG値に関与するフィールドがドキュメントから削除されると、エラーが発生します。 -
二面性ビューに同じビューの主キーまたは一意キーを参照する外部キーを持つ基礎となる表がある場合、ドキュメント更新操作(更新、挿入または削除)では、その主キーまたは一意キーの値を変更できません。これを試行すると、エラーが発生します。
-
ドキュメント更新操作(更新、挿入または削除)に基礎となる表の同じ行の更新が含まれる場合、その行の内容は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} ]}');
-
更新操作(更新、挿入または削除)のために送信されるドキュメントに埋め込まれた
etag
フィールド値が現在のデータベース状態と一致しない場合は、エラーが発生します。 -
ドキュメント更新操作(更新、挿入または削除)が、同じ二面性ビューでサポートされる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.
親トピック: 更新可能なJSONリレーショナル二面性ビュー