游標類型 (SQLSRV 驅動程式)

下載 PHP 驅動程式

SQLSRV 驅動程式可讓您根據資料指標類型,建立能夠以任何順序存取資料列的結果集。 本主題將探討用戶端(緩衝)與伺服器端(未緩衝)游標。

游標類型

當您使用 sqlsrv_query 或 sqlsrv_prepare 建立結果集時,您可以指定游標類型。 預設會使用只能向前的游標,讓您從結果集的第一個資料列開始,每次移動一個資料列,直到到達結果集結尾。

您可以搭配可捲動的資料指標建立結果集,其可讓您以任何順序存取結果集中的任何資料列。 下表列出可傳遞至 sqlsrv_query 或 sqlsrv_prepare 中 Scrollable 選項的值。

選項 描述
SQLSRV_CURSOR_FORWARD 可讓您從結果集的第一個資料列開始,一次移動一個資料列,直到到達結果集末尾。

這是預設的游標類型。

sqlsrv_num_rows 會對使用此游標類型建立的結果集傳回錯誤。

forward 是 SQLSRV_CURSOR_FORWARD 的縮寫格式。
SQLSRV_CURSOR_STATIC 讓您以任何順序存取資料列,但將不會反映資料庫中的變更。

static 是 SQLSRV_CURSOR_STATIC 的縮寫格式。
SQLSRV_CURSOR_DYNAMIC 讓您以任何順序存取資料列,且會反映資料庫中的變更。

sqlsrv_num_rows 會針對使用此游標類型建立的結果集傳回錯誤。

dynamic 是 SQLSRV_CURSOR_DYNAMIC 的縮寫格式。
SQLSRV_CURSOR_KEYSET 讓您以任何順序存取資料列。 不過,如果某個資料列已從資料表中刪除,則索引鍵集資料指標不會更新資料列數(已刪除的資料列會在傳回時不含任何值)。

keyset 是 SQLSRV_CURSOR_KEYSET 的縮寫格式。
SQLSRV_CURSOR_CLIENT_BUFFERED 讓您以任何順序存取資料列。 建立用戶端游標查詢。

buffered 是 SQLSRV_CURSOR_CLIENT_BUFFERED 的縮寫格式。

如果查詢會產生多個結果集,Scrollable 選項便會套用到所有結果集。

選取結果集中的資料列

在您建立結果集之後,您可以使用 sqlsrv_fetch、sqlsrv_fetch_array 或 sqlsrv_fetch_object 來指定資料列。

下表描述可在 row 參數中指定的值。

參數 描述
SQLSRV_SCROLL_NEXT 指定下一個資料列。 如果您未為可捲動結果集指定 row 參數,這就是預設值。
SQLSRV_SCROLL_PRIOR 指定目前資料列的前一列。
SQLSRV_SCROLL_FIRST 指定結果集中的第一個資料列。
SQLSRV_SCROLL_LAST 指定結果集中的最後一個資料列。
SQLSRV_SCROLL_ABSOLUTE 指定由 offset 參數指定的資料列。
SQLSRV_SCROLL_RELATIVE 指定從目前資料列起算、由 offset 參數指定的資料列。

伺服器端游標與 SQLSRV 驅動程式

下列範例顯示各種游標的效果。 在範例的第 33 行,您會看到三個指定不同游標的查詢陳述中的第一個。 兩個查詢陳述式已加上註解。 每次執行程式時,請使用不同的游標類型,以查看第 47 行中的資料庫更新效果。

<?php  
$server = "server_name";  
$conn = sqlsrv_connect( $server, array( 'Database' => 'test' ));  
if ( $conn === false ) {  
   die( print_r( sqlsrv_errors(), true ));  
}  
  
$stmt = sqlsrv_query( $conn, "DROP TABLE dbo.ScrollTest" );  
if ( $stmt !== false ) {   
   sqlsrv_free_stmt( $stmt );   
}  
  
$stmt = sqlsrv_query( $conn, "CREATE TABLE ScrollTest (id int, value char(10))" );  
if ( $stmt === false ) {  
   die( print_r( sqlsrv_errors(), true ));  
}  
  
$stmt = sqlsrv_query( $conn, "INSERT INTO ScrollTest (id, value) VALUES(?,?)", array( 1, "Row 1" ));  
if ( $stmt === false ) {  
   die( print_r( sqlsrv_errors(), true ));  
}  
  
$stmt = sqlsrv_query( $conn, "INSERT INTO ScrollTest (id, value) VALUES(?,?)", array( 2, "Row 2" ));  
if ( $stmt === false ) {  
   die( print_r( sqlsrv_errors(), true ));  
}  
  
$stmt = sqlsrv_query( $conn, "INSERT INTO ScrollTest (id, value) VALUES(?,?)", array( 3, "Row 3" ));  
if ( $stmt === false ) {  
   die( print_r( sqlsrv_errors(), true ));  
}  
  
$stmt = sqlsrv_query( $conn, "SELECT * FROM ScrollTest", array(), array( "Scrollable" => 'keyset' ));  
// $stmt = sqlsrv_query( $conn, "SELECT * FROM ScrollTest", array(), array( "Scrollable" => 'dynamic' ));  
// $stmt = sqlsrv_query( $conn, "SELECT * FROM ScrollTest", array(), array( "Scrollable" => 'static' ));  
  
$rows = sqlsrv_has_rows( $stmt );  
if ( $rows != true ) {  
   die( "Should have rows" );  
}  
  
$result = sqlsrv_fetch( $stmt, SQLSRV_SCROLL_LAST );  
$field1 = sqlsrv_get_field( $stmt, 0 );  
$field2 = sqlsrv_get_field( $stmt, 1 );  
echo "\n$field1 $field2\n";  
  
$stmt2 = sqlsrv_query( $conn, "delete from ScrollTest where id = 3" );  
// or  
// $stmt2 = sqlsrv_query( $conn, "UPDATE ScrollTest SET id = 4 WHERE id = 3" );  
if ( $stmt2 !== false ) {   
   sqlsrv_free_stmt( $stmt2 );   
}  
  
$result = sqlsrv_fetch( $stmt, SQLSRV_SCROLL_LAST );  
$field1 = sqlsrv_get_field( $stmt, 0 );  
$field2 = sqlsrv_get_field( $stmt, 1 );  
echo "\n$field1 $field2\n";  
  
sqlsrv_free_stmt( $stmt );  
sqlsrv_close( $conn );  
?>  

用戶端游標和 SQLSRV 驅動程式

用戶端游標是 Microsoft Drivers for PHP for SQL Server 3.0 版新增的一項功能,可讓您將整個結果集快取於記憶體中。 使用用戶端游標時,執行查詢後即可取得資料列數。

用戶端游標應用於小型到中型的結果集。 對於大型結果集,請使用伺服器端游標。

如果緩衝區因為不夠大而無法保存整個結果集,查詢將會傳回 false。 您可以將緩衝區大小上限提高到 PHP 記憶體限制。

透過使用 SQLSRV 驅動程式,您可以使用 sqlsrv_configure 的 ClientBufferMaxKBSize 設定來設定保存結果集的緩衝區大小。 sqlsrv_get_config 會傳回 ClientBufferMaxKBSize 的值。 您也可以在 php.ini 檔案中使用 sqlsrv.ClientBufferMaxKBSize 來設定緩衝區大小上限 (例如 sqlsrv.ClientBufferMaxKBSize = 1024)。

下列範例顯示︰

  • 使用用戶端游標時,永遠都可以取得資料列數。

  • 用戶端游標和批次敘述的使用。

<?php  
$serverName = "(local)";  
$connectionInfo = array("Database"=>"AdventureWorks");  
$conn = sqlsrv_connect( $serverName, $connectionInfo);  
  
if ( $conn === false ) {  
   echo "Could not connect.\n";  
   die( print_r( sqlsrv_errors(), true));  
}  
  
$tsql = "select * from HumanResources.Department";  
  
// Execute the query with client-side cursor.  
$stmt = sqlsrv_query($conn, $tsql, array(), array("Scrollable"=>"buffered"));  
if (! $stmt) {  
   echo "Error in statement execution.\n";  
   die( print_r( sqlsrv_errors(), true));  
}  
  
// row count is always available with a client-side cursor  
$row_count = sqlsrv_num_rows( $stmt );  
echo "\nRow count = $row_count\n";  
  
// Move to a specific row in the result set.  
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_FIRST);  
$EmployeeID = sqlsrv_get_field( $stmt, 0);  
echo "Employee ID = $EmployeeID \n";  
  
// Client-side cursor and batch statements  
$tsql = "select top 2 * from HumanResources.Employee;Select top 3 * from HumanResources.EmployeeAddress";  
  
$stmt = sqlsrv_query($conn, $tsql, array(), array("Scrollable"=>"buffered"));  
if (! $stmt) {  
   echo "Error in statement execution.\n";  
   die( print_r( sqlsrv_errors(), true));  
}  
  
$row_count = sqlsrv_num_rows( $stmt );  
echo "\nRow count for first result set = $row_count\n";  
  
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_FIRST);  
$EmployeeID = sqlsrv_get_field( $stmt, 0);  
echo "Employee ID = $EmployeeID \n";  
  
sqlsrv_next_result($stmt);  
  
$row_count = sqlsrv_num_rows( $stmt );  
echo "\nRow count for second result set = $row_count\n";  
  
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_LAST);  
$EmployeeID = sqlsrv_get_field( $stmt, 0);  
echo "Employee ID = $EmployeeID \n";  
?>  

下列範例顯示一個使用 sqlsrv_prepare 且採用不同用戶端緩衝區大小的用戶端游標。

<?php  
$serverName = "(local)";  
$connectionInfo = array( "Database"=>"AdventureWorks");  
$conn = sqlsrv_connect( $serverName, $connectionInfo);  
  
if ( $conn === false ) {  
   echo "Could not connect.\n";  
   die( print_r( sqlsrv_errors(), true));  
}  
  
$tsql = "select * from HumanResources.Employee";  
$stmt = sqlsrv_prepare( $conn, $tsql, array(), array("Scrollable" => SQLSRV_CURSOR_CLIENT_BUFFERED, "ClientBufferMaxKBSize" => 51200));
  
if (! $stmt ) {  
   echo "Statement could not be prepared.\n";  
   die( print_r( sqlsrv_errors(), true));  
}  
  
sqlsrv_execute( $stmt);  
  
$row_count = sqlsrv_num_rows( $stmt );  
if ($row_count)  
   echo "\nRow count = $row_count\n";  
  
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_FIRST);  
if ($row ) {  
   $EmployeeID = sqlsrv_get_field( $stmt, 0);  
   echo "Employee ID = $EmployeeID \n";  
}  
?>