Share via


位置指定の UPDATE および DELETE ステートメントのシミュレート

データ ソースが配置された更新および削除ステートメントをサポートしていない場合、ドライバーはこれらをシミュレートできます。 たとえば、ODBC カーソル ライブラリは、配置された更新ステートメントと削除ステートメントをシミュレートします。 位置指定更新および削除ステートメントをシミュレートするための一般的な方法は、位置指定されたステートメントを検索されたステートメントに変換する方法です。 これを行うには、WHERE CURRENT OF 句を、現在の行を識別する検索された WHERE 句に置き換えます。

たとえば、CustID 列は Customers テーブルの各行を一意に識別するため、位置指定された削除ステートメント

DELETE FROM Customers WHERE CURRENT OF CustCursor  

は、次のように変換される場合があります。

DELETE FROM Customers WHERE (CustID = ?)  

ドライバーは、WHERE 句で次のいずれかの 行識別子 (ROWID) を使用できます。

  • テーブル内のすべての行を一意に識別する値を持つ列。 たとえば、SQL_BEST_ROWID で SQLSpecialColumns を呼び出すと、この目的を果たす最適な列または列のセットが返されます。

  • すべての行を一意に識別するために、一部のデータ ソースによって提供される擬似列。 これらは、SQLSpecialColumns を呼び出すことによって取得することもできます。

  • 一意なインデックス (使用可能な場合)。

  • 結果セット内のすべての列。

ドライバーが構築する WHERE 句で使用する必要がある列は、ドライバーによって異なります。 一部のデータ ソースでは、行識別子 (ROWID) の決定にコストがかかる場合があります。 ただし、実行する速度が速く、シミュレートされたステートメントで最大 1 行の更新または削除が行われることが保証されます。 基になる DBMS の機能によっては、行識別子 (ROWID) を使用すると設定にコストがかかる場合があります。 ただし、実行する速度が速く、シミュレートされたステートメントで 1 つの行のみ更新または削除が行われることが保証されます。 結果セット内のすべての列を使用するオプションは、通常、設定がはるかに簡単です。 ただし、実行に時間がかかり、列が行を一意に識別しない場合、特に結果セットの選択リストに基になるテーブルに存在するすべての列が含まれていない場合、行が意図せずに更新または削除される可能性があります。

ドライバーでサポートされている上記の戦略に応じて、アプリケーションは、SQL_ATTR_SIMULATE_CURSOR ステートメント属性でドライバーを使用する戦略を選択できます。 アプリケーションが意図せずに行を更新または削除するリスクは奇妙に思えるかもしれませんが、結果セット内の列で結果セット内の各行が一意に識別されるようにすることで、このリスクを回避できます。 これにより、ドライバーはこれを行う必要がある作業を省くことができます。

ドライバーは、行識別子 (ROWID) を使用することを選択した場合、結果セットを作成する SELECT FOR UPDATE ステートメントをインターセプトします。 選択リストの列で行が効果的に識別されない場合、ドライバーは選択リストの末尾に必要な列を追加します。 一部のデータ ソースには、Oracle の ROWID 列など、常に行を一意に識別する単一の列があります。このような列が使用可能な場合、ドライバーはこれを使用します。 それ以外の場合、ドライバーは FROM 句の各テーブルの SQLSpecialColumns を呼び出して、各行を一意に識別する列の一覧を取得します。 この手法の結果として生じる一般的な制限は、FROM 句に複数のテーブルがある場合にカーソル シミュレーションが失敗することです。

ドライバーが行を識別する方法に関係なく、通常は、データ ソースに送信する前に、SELECT FOR UPDATE ステートメントから FOR UPDATE OF 句を削除します。 FOR UPDATE OF 句は、位置指定の更新および削除ステートメントでのみ使用されます。 位置指定の更新および削除ステートメントをサポートしていないデータ ソースは、通常、それをサポートしていません。

アプリケーションが実行のために位置指定された更新または削除ステートメントを送信すると、ドライバーは WHERE CURRENT OF 句を行識別子 (ROWID) を含む WHERE 句に置き換えます。 これらの列の値は、WHERE 句で使用する各列のドライバーによって保持されるキャッシュから取得されます。 ドライバーは WHERE 句を置き換えた後、ステートメントをデータ ソースに送信して実行します。

たとえば、アプリケーションが次のステートメントを送信して結果セットを作成するとします。

SELECT Name, Address, Phone FROM Customers FOR UPDATE OF Phone, Address  

アプリケーションが一意性の保証を要求する SQL_ATTR_SIMULATE_CURSOR を設定しており、データ ソースが常に行を一意に識別する擬似列を提供しない場合、ドライバーは Customers テーブルの SQLSpecialColumns を呼び出し、CustID が Customers テーブルの鍵であることを検出し、これを選択リストに追加します。 FOR UPDATE OF 句を削除します。

SELECT Name, Address, Phone, CustID FROM Customers  

アプリケーションが一意性の保証を要求していない場合、ドライバーは FOR UPDATE OF 句のみを削除します。

SELECT Name, Address, Phone FROM Customers  

アプリケーションが結果セットをスクロールし、実行のために次の位置指定された更新ステートメントを送信するとします。Cust は結果セット上のカーソルの名前です。

UPDATE Customers SET Address = ?, Phone = ? WHERE CURRENT OF Cust  

アプリケーションが一意性の保証を要求していない場合、ドライバーは WHERE 句を置き換え、CustID パラメーターをキャッシュ内の変数にバインドします。

UPDATE Customers SET Address = ?, Phone = ? WHERE (CustID = ?)  

アプリケーションが一意性の保証を要求していない場合、ドライバーは WHERE 句を置き換え、この句の Name、Address、Phone のパラメーターをキャッシュ内の変数にバインドします。

UPDATE Customers SET Address = ?, Phone = ?  
   WHERE (Name = ?) AND (Address = ?) AND (Phone = ?)