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

アプリケーションは、配置された更新または削除ステートメントを使用して、結果セット内の現在の行を更新または削除できます。 位置指定の更新および削除ステートメントは、一部のデータ ソースでサポートされていますが、一部のデータ ソースではサポートされていません。 データ ソースが位置指定された更新ステートメントと delete ステートメントをサポートしているかどうかを判断するために、アプリケーションは、(カーソルの種類に応じて) インフォタイプSQL_DYNAMIC_CURSOR_ATTRIBUTES1、SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1、SQL_KEYSET_CURSOR_ATTRIBUTES1、またはSQL_STATIC_CURSOR_ATTRIBUTES1を使用して SQLGetInfo を呼び出します。 ODBC カーソル ライブラリでは、配置された更新ステートメントと delete ステートメントがシミュレートされることに注意してください。

配置された更新ステートメントまたは delete ステートメントを使用するには、SELECT FOR UPDATE ステートメントを使用して結果セットを作成する必要があります。 このステートメントの構文は次のとおりです。

SELECT [ALLDISTINCT | ] select-list

FROMtable-reference-list

[WHEREsearch-condition]

FOR UPDATE OF [列名 [,列名]...

次に、更新または削除する行にカーソルを置きます。 これを行うには、 SQLFetchScroll を呼び出して、必要な行を含む行セットを取得し、 SQLSetPos を 呼び出してその行に行セット カーソルを配置します。 その後、アプリケーションは、結果セットで使用されているステートメントとは異なるステートメントに対して、位置指定された更新または削除ステートメントを実行します。 これらのステートメントの構文は次のとおりです。

UPDATEtable-name

SETcolumn-identifier= {expressionNULL | }

[,column-identifier= { | NULL}]...

WHERE CURRENTOFcursor-name

DELETEFROMtable-nameWHERECURRENTOFcursor-name

これらのステートメントにはカーソル名が必要であることに注意してください。 アプリケーションは、結果セットを作成するステートメントを実行する前に SQLSetCursorName でカーソル名を指定することも、カーソルの作成時にデータ ソースにカーソル名を自動的に生成させることができます。 後者の場合、アプリケーションは 、SQLGetCursorName を呼び出すことによって、位置指定の更新および delete ステートメントで使用するためにこのカーソル名を取得します。

たとえば、次のコードを使用すると、ユーザーは Customers テーブルをスクロールして顧客レコードを削除したり、住所や電話番号を更新したりできます。 SQLSetCursorName を呼び出して、結果セットを作成する前にカーソル名を指定し、結果セットに hstmtCust、位置指定 update ステートメントに hstmtUpdate、位置指定された delete ステートメントに hstmtDelete という 3 つのステートメント ハンドルを使用します。 コードは、配置された update ステートメント内のパラメーターに個別の変数をバインドできますが、行セット バッファーを更新し、これらのバッファーの要素をバインドします。 これにより、行セット バッファーが更新されたデータと同期されます。

#define POSITIONED_UPDATE 100  
#define POSITIONED_DELETE 101  
  
SQLUINTEGER    CustIDArray[10];  
SQLCHAR        NameArray[10][51], AddressArray[10][51],   
               PhoneArray[10][11];  
SQLINTEGER     CustIDIndArray[10], NameLenOrIndArray[10],   
               AddressLenOrIndArray[10],  
               PhoneLenOrIndArray[10];  
SQLUSMALLINT   RowStatusArray[10], Action, RowNum;  
SQLHSTMT       hstmtCust, hstmtUpdate, hstmtDelete;  
  
// Set the SQL_ATTR_BIND_TYPE statement attribute to use column-wise   
// binding. Declare the rowset size with the SQL_ATTR_ROW_ARRAY_SIZE   
// statement attribute. Set the SQL_ATTR_ROW_STATUS_PTR statement   
// attribute to point to the row status array.  
SQLSetStmtAttr(hstmtCust, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);  
SQLSetStmtAttr(hstmtCust, SQL_ATTR_ROW_ARRAY_SIZE, 10, 0);  
SQLSetStmtAttr(hstmtCust, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);  
  
// Bind arrays to the CustID, Name, Address, and Phone columns.  
SQLBindCol(hstmtCust, 1, SQL_C_ULONG, CustIDArray, 0, CustIDIndArray);  
SQLBindCol(hstmtCust, 2, SQL_C_CHAR, NameArray, sizeof(NameArray[0]),  
            NameLenOrIndArray);  
SQLBindCol(hstmtCust, 3, SQL_C_CHAR, AddressArray, sizeof(AddressArray[0]),  
         AddressLenOrIndArray);  
SQLBindCol(hstmtCust, 4, SQL_C_CHAR, PhoneArray, sizeof(PhoneArray[0]),  
            PhoneLenOrIndArray);  
  
// Set the cursor name to Cust.  
SQLSetCursorName(hstmtCust, "Cust", SQL_NTS);  
  
// Prepare positioned update and delete statements.  
SQLPrepare(hstmtUpdate,  
   "UPDATE Customers SET Address = ?, Phone = ? WHERE CURRENT OF Cust",  
   SQL_NTS);  
SQLPrepare(hstmtDelete, "DELETE FROM Customers WHERE CURRENT OF Cust", SQL_NTS);  
  
// Execute a statement to retrieve rows from the Customers table.  
SQLExecDirect(hstmtCust,  
   "SELECT CustID, Name, Address, Phone FROM Customers FOR UPDATE OF Address, Phone",  
   SQL_NTS);  
  
// Fetch and display the first 10 rows.  
SQLFetchScroll(hstmtCust, SQL_FETCH_NEXT, 0);  
DisplayData(CustIDArray, CustIDIndArray, NameArray, NameLenOrIndArray, AddressArray,  
            AddressLenOrIndArray, PhoneArray, PhoneLenOrIndArray, RowStatusArray);  
  
// Call GetAction to get an action and a row number from the user.  
while (GetAction(&Action, &RowNum)) {  
   switch (Action) {  
  
      case SQL_FETCH_NEXT:  
      case SQL_FETCH_PRIOR:  
      case SQL_FETCH_FIRST:  
      case SQL_FETCH_LAST:  
      case SQL_FETCH_ABSOLUTE:  
      case SQL_FETCH_RELATIVE:  
         // Fetch and display the requested data.  
         SQLFetchScroll(hstmtCust, Action, RowNum);  
         DisplayData(CustIDArray, CustIDIndArray, NameArray, NameLenOrIndArray,  
                     AddressArray, AddressLenOrIndArray, PhoneArray,  
                     PhoneLenOrIndArray, RowStatusArray);  
         break;  
  
      case POSITIONED_UPDATE:  
         // Get the new data and place it in the rowset buffers.  
         GetNewData(AddressArray[RowNum - 1], &AddressLenOrIndArray[RowNum - 1],  
                     PhoneArray[RowNum - 1], &PhoneLenOrIndArray[RowNum - 1]);  
  
         // Bind the elements of the arrays at position RowNum-1 to the   
         // parameters of the positioned update statement.  
         SQLBindParameter(hstmtUpdate, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,  
                           50, 0, AddressArray[RowNum - 1], sizeof(AddressArray[0]),  
                           &AddressLenOrIndArray[RowNum - 1]);  
         SQLBindParameter(hstmtUpdate, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,  
                           10, 0, PhoneArray[RowNum - 1], sizeof(PhoneArray[0]),  
                           &PhoneLenOrIndArray[RowNum - 1]);  
  
         // Position the rowset cursor. The rowset is 1-based.  
         SQLSetPos(hstmtCust, RowNum, SQL_POSITION, SQL_LOCK_NO_CHANGE);  
  
         // Execute the positioned update statement to update the row.  
         SQLExecute(hstmtUpdate);  
         break;  
  
      case POSITIONED_DELETE:  
         // Position the rowset cursor. The rowset is 1-based.  
         SQLSetPos(hstmtCust, RowNum, SQL_POSITION, SQL_LOCK_NO_CHANGE);  
  
         // Execute the positioned delete statement to delete the row.  
         SQLExecute(hstmtDelete);  
         break;  
   }  
}  
  
// Close the cursor.  
SQLCloseCursor(hstmtCust);