CURSOR STATUS: примеры (SQL)

Функция CURSOR_STATUS для определения состояния курсора
Раздел: Функции работы с курсорами
CURSOR_STATUS({'local', 'cursor_name'} | {'global', 'cursor_name'} | {'variable', 'cursor_variable'}): smallint

Функция CURSOR_STATUS в MS SQL Server

Функция CURSOR_STATUS определяет состояние курсора в Microsoft SQL Server. Она возвращает информацию о том, готов ли курсор к использованию, содержит ли строки, или возникли ошибки при его работе.

Функцию применяют для проверки состояния курсора перед операциями чтения или модификации. Это помогает избежать ошибок при обработке данных и управлять потоком выполнения скриптов.

Синтаксис и аргументы

Синтаксис функции: CURSOR_STATUS ( 'тип', 'имя_курсора' ).

Первый аргумент задает тип курсора:

  • 'local' — определяет локальный курсор.
  • 'global' — определяет глобальный курсор.
  • 'variable' — определяет курсор, связанный с переменной.

Второй аргумент задает имя курсора или переменной курсора.

Возвращаемые значения

  • 1 — курсор открыт и содержит строки.
  • 0 — курсор открыт, но не содержит строк.
  • -1 — курсор закрыт.
  • -2 — курсор не существует.
  • -3 — курсор с указанным именем не существует.

Примеры использования CURSOR_STATUS

Проверка состояния глобального курсора.

DECLARE @status INT;
DECLARE cursor_example CURSOR FOR SELECT 1 AS value;
OPEN cursor_example;
SET @status = CURSOR_STATUS('global', 'cursor_example');
SELECT @status AS status;
CLOSE cursor_example;
DEALLOCATE cursor_example;
status
1

Проверка состояния курсора после закрытия.

DECLARE @status INT;
DECLARE cursor_example CURSOR FOR SELECT 1 AS value;
OPEN cursor_example;
CLOSE cursor_example;
SET @status = CURSOR_STATUS('global', 'cursor_example');
SELECT @status AS status;
DEALLOCATE cursor_example;
status
-1

Проверка состояния несуществующего курсора.

SELECT CURSOR_STATUS('global', 'nonexistent_cursor') AS status;
status
-3

Альтернативные функции в MS SQL Server

В MS SQL Server есть несколько функций для работы с курсорами:

  • @@FETCH_STATUS — проверяет успешность последней операции FETCH. Возвращает 0 при успешном чтении, -1 при ошибке или отсутствии строк, -2 при удалении строки.
  • @@CURSOR_ROWS — возвращает количество строк в последнем открытом курсоре.

Функцию @@FETCH_STATUS используют в циклах для контроля чтения данных. Функцию @@CURSOR_ROWS применяют для получения информации о размере результирующего набора. CURSOR_STATUS дает общее состояние курсора, что полезно для проверки перед началом операций.

Аналоги функции в других СУБД

В других системах управления базами данных есть похожие механизмы.

Oracle

В Oracle используют атрибуты курсора %ISOPEN, %FOUND, %NOTFOUND, %ROWCOUNT.

DECLARE
  CURSOR cur IS SELECT 1 FROM dual;
  val NUMBER;
BEGIN
  OPEN cur;
  IF cur%ISOPEN THEN
    FETCH cur INTO val;
  END IF;
  CLOSE cur;
END;

PostgreSQL

В PostgreSQL применяют функцию pg_cursor или проверяют состояние с помощью исключений.

DECLARE cur CURSOR FOR SELECT 1;
OPEN cur;
-- Проверка через исключение при FETCH
FETCH cur;
-- Если строк нет, то будет исключение
CLOSE cur;

MySQL

В MySQL используют обработчики для контроля состояния курсора.

DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR SELECT 1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
-- После FETCH проверяют переменную done
CLOSE cur;

Типичные ошибки при использовании CURSOR_STATUS

Распространенная ошибка — использование неверного типа курсора.

DECLARE @cursor_var CURSOR;
SET @cursor_var = CURSOR FOR SELECT 1;
OPEN @cursor_var;
-- Ошибка: вместо 'variable' указан 'global'
SELECT CURSOR_STATUS('global', '@cursor_var') AS status;
status
-3

Попытка проверки состояния после освобождения курсора.

DECLARE cursor_example CURSOR FOR SELECT 1;
OPEN cursor_example;
CLOSE cursor_example;
DEALLOCATE cursor_example;
-- Курсор уже не существует
SELECT CURSOR_STATUS('global', 'cursor_example') AS status;
status
-3

Использование функции без указания кавычек в аргументах.

DECLARE cursor_example CURSOR FOR SELECT 1;
OPEN cursor_example;
-- Ошибка синтаксиса
SELECT CURSOR_STATUS(global, cursor_example) AS status;
Сообщение об ошибке синтаксиса.

Изменения в последних версиях MS SQL Server

Функция CURSOR_STATUS не претерпела значительных изменений в последних версиях MS SQL Server. Ее поведение остается стабильным с момента появления. В документации Microsoft не указаны модификации функции для версий SQL Server 2016, 2017, 2019 и 2022.

Однако, в современных версиях SQL Server рекомендуют по возможности избегать использования курсоров в пользу операций над множествами, что связано с оптимизацией производительности.

Расширенные примеры использования CURSOR_STATUS

Использование в процедуре для безопасной обработки данных.

Пример sql
CREATE PROCEDURE ProcessData AS
BEGIN
    DECLARE @cursor CURSOR;
    DECLARE @id INT;
    SET @cursor = CURSOR FOR SELECT Id FROM SomeTable;
    OPEN @cursor;
    IF CURSOR_STATUS('variable', '@cursor') = 1
    BEGIN
        FETCH NEXT FROM @cursor INTO @id;
        WHILE @@FETCH_STATUS = 0
        BEGIN
            PRINT 'Processing ID: ' + CAST(@id AS VARCHAR);
            FETCH NEXT FROM @cursor INTO @id;
        END
    END
    ELSE
        PRINT 'Cursor is not ready.';
    CLOSE @cursor;
    DEALLOCATE @cursor;
END;

Проверка состояния курсора внутри транзакции с откатом.

Пример sql
BEGIN TRANSACTION;
DECLARE @cursor CURSOR;
SET @cursor = CURSOR FOR SELECT 1/0; -- Деление на ноль
BEGIN TRY
    OPEN @cursor;
END TRY
BEGIN CATCH
    SELECT CURSOR_STATUS('variable', '@cursor') AS status_in_catch;
END CATCH
-- Курсор остается закрытым из-за ошибки
SELECT CURSOR_STATUS('variable', '@cursor') AS status_after_try;
ROLLBACK TRANSACTION;
status_in_catch
-1
status_after_try
-1

Использование с динамическим SQL.

Пример sql
DECLARE @cursor_name SYSNAME = 'global_cursor';
DECLARE @sql NVARCHAR(MAX);
SET @sql = 'DECLARE ' + @cursor_name + ' CURSOR FOR SELECT 1; OPEN ' + @cursor_name + ';';
EXEC sp_executesql @sql;
-- Проверка состояния курсора, созданного динамически
SELECT CURSOR_STATUS('global', @cursor_name) AS status;
status
1

MS SQL CURSOR_STATUS function comments

En
CURSOR STATUS Allows the caller of a stored procedure to determine whether the procedure has returned a cursor and result set