使用 SQLSetPos 更新資料列集中的資料列
SQLSetPos 進行更新作業時,資料來源會使用各繫結資料行的應用程式緩衝區資料,更新資料表的一或多個已選取資料列,但長度/指標緩衝區的值為 SQL_COLUMN_IGNORE 時,則不會更新。 未繫結的資料行也不會更新。
若要使用 SQLSetPos 更新資料列,應用程式會執行下列動作:
將新的資料值放在資料列集緩衝區中。 如需如何使用 SQLSetPos 傳送長資料的資訊,請參閱長資料、SQLSetPos 與 SQLBulkOperations (機器翻譯)。
請視需要設定每個資料行的長度/指標緩衝區中的值。 這個值會是繫結至字串緩衝區之資料行的資料或 SQL_NTS 位元組長度,或繫結至二進位緩衝區之資料行的資料位元組長度。如果資料行要設為 Null,則會是 SQL_Null_DATA。
設定要更新為 SQL_COLUMN_IGNORE 的資料行長度/指標緩衝區中的值。 雖然應用程式可以略過此步驟,並重新傳送現有的資料,但這麼做效率不高,也可能將值傳送至讀取時被截斷的資料來源。
以設定為 SQL_UPDATE 的 Operation,以及設定為待更新資料列數量的 RowNumber,呼叫 SQLSetPos。 如果 RowNumber 是 0,將會更新資料列集內的所有資料列。
在 SQLSetPos 傳回之後,目前的資料列會設定為更新的資料列。
更新資料列集的所有資料列 (RowNumber 等於 0) 時,應用程式可將資料列操作陣列 (SQL_ATTR_ROW_OPERATION_PTR 陳述式屬性指向的陣列) 的對應元素,設定為 SQL_ROW_IGNORE,藉此停用特定資料列的更新。 資料列作業陣列的大小和元素數目,都會對應至 SQL_ATTR_ROW_STATUS_PTR 陳述式屬性所指向的資料列狀態陣列。 若只更新已成功擷取,且尚未從資料列集刪除的結果集中的資料列,應用程式會從擷取資料列集做為 SQLSetPos 資料列作業陣列的函式中,使用其資料列狀態陣列。
對於傳送至資料來源做為更新的每個資料列,應用程式緩衝區都應有屬於有效的資料列資料。 如果應用程式緩衝區已藉由擷取方式來填滿,而且已經維護資料列狀態陣列,則其在每一個資料列位置的值,都不應該是 SQL_ROW_DELETED、SQL_ROW_ERROR 或 SQL_ROW_NOROW。
例如,下列程式碼可讓使用者捲動 Customers 資料表,並更新、刪除或新增資料列。 此程式碼會在呼叫 SQLSetPos 以更新或新增資料列之前,將新資料放在資料列集緩衝區中。 資料列集緩衝區結尾會配置額外的資料列,以保存新的資料列。這可防止在緩衝區中放置新資料列的資料時,覆寫現有的資料。
#define UPDATE_ROW 100
#define DELETE_ROW 101
#define ADD_ROW 102
SQLUINTEGER CustIDArray[11];
SQLCHAR NameArray[11][51], AddressArray[11][51],
PhoneArray[11][11];
SQLINTEGER CustIDIndArray[11], NameLenOrIndArray[11],
AddressLenOrIndArray[11],
PhoneLenOrIndArray[11];
SQLUSMALLINT RowStatusArray[10], Action, RowNum;
SQLRETURN rc;
SQLHSTMT hstmt;
// Set the SQL_ATTR_ROW_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(hstmt, SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, 10, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);
// Bind arrays to the CustID, Name, Address, and Phone columns.
SQLBindCol(hstmt, 1, SQL_C_ULONG, CustIDArray, 0, CustIDIndArray);
SQLBindCol(hstmt, 2, SQL_C_CHAR, NameArray, sizeof(NameArray[0]), NameLenOrIndArray);
SQLBindCol(hstmt, 3, SQL_C_CHAR, AddressArray, sizeof(AddressArray[0]),
AddressLenOrIndArray);
SQLBindCol(hstmt, 4, SQL_C_CHAR, PhoneArray, sizeof(PhoneArray[0]),
PhoneLenOrIndArray);
// Execute a statement to retrieve rows from the Customers table.
SQLExecDirect(hstmt, "SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS);
// Fetch and display the first 10 rows.
rc = SQLFetchScroll(hstmt, 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(hstmt, Action, RowNum);
DisplayData(CustIDArray, CustIDIndArray,
NameArray, NameLenOrIndArray,
AddressArray, AddressLenOrIndArray,
PhoneArray, PhoneLenOrIndArray, RowStatusArray);
break;
case UPDATE_ROW:
// Place the new data in the rowset buffers and update the
// specified row.
GetNewData(&CustIDArray[RowNum - 1], &CustIDIndArray[RowNum - 1],
NameArray[RowNum - 1], &NameLenOrIndArray[RowNum - 1],
AddressArray[RowNum - 1], &AddressLenOrIndArray[RowNum - 1],
PhoneArray[RowNum - 1], &PhoneLenOrIndArray[RowNum - 1]);
SQLSetPos(hstmt, RowNum, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
break;
case DELETE_ROW:
// Delete the specified row.
SQLSetPos(hstmt, RowNum, SQL_DELETE, SQL_LOCK_NO_CHANGE);
break;
case ADD_ROW:
// Place the new data in the rowset buffers at index 10.
// This is an extra element for new rows so rowset data is
// not overwritten. Insert the new row. Row 11 corresponds
// to index 10.
GetNewData(&CustIDArray[10], &CustIDIndArray[10],
NameArray[10], &NameLenOrIndArray[10],
AddressArray[10], &AddressLenOrIndArray[10],
PhoneArray[10], &PhoneLenOrIndArray[10]);
SQLSetPos(hstmt, 11, SQL_ADD, SQL_LOCK_NO_CHANGE);
break;
}
}
// Close the cursor.
SQLCloseCursor(hstmt);