Типы курсоров (драйвер SQLSRV)

Скачать драйвер PHP

Драйвер SQLSRV позволяет создать результирующий набор со строками, доступ к которым можно осуществлять в любом порядке в зависимости от типа курсора. В этой статье рассматриваются клиентские (в буфере) и серверные курсоры (без буферизации).

Типы курсоров

При создании результирующего набора с помощью sqlsrv_query или sqlsrv_prepare можно указать тип курсора. По умолчанию используется курсор последовательного доступа, который позволяет переместить одну строку за раз, начиная с первой строки результирующего набора и до его конца.

Можно создать результирующий набор с прокручиваемым курсором, который позволяет получить доступ к любой строке в результирующем наборе в любом порядке. В следующей таблице перечислены значения, которые можно передать в параметре Scrollable в sqlsrv_query или sqlsrv_prepare.

Параметр Описание
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 SQL Server для PHP версии 3.0. Они позволяют кэшировать в памяти весь результирующий набор. Число строк доступно после выполнения запроса при использовании курсора на стороне клиента.

Курсоры на стороне клиента следует использовать только для малых и средних результирующих наборов. Используйте курсоры на стороне сервера для больших результирующих наборов.

Запрос возвратит значение false, если буфер недостаточно большой для хранения всего результирующего набора. Вы можете увеличить размер этого буфера вплоть до максимального объема памяти PHP.

С помощью драйвера SQLSRV можно настроить размер буфера, содержащего результирующий набор. Для этого нужно задать параметр ClientBufferMaxKBSize для sqlsrv_configure. 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";  
}  
?>  

См. также:

Указание типа курсора и выбор строк