Sql

Cursor sql: Как использовать курсор в функциях на PL/pgSQL? | Info-Comp.ru

Содержание

Как использовать курсор в функциях на PL/pgSQL? | Info-Comp.ru

И снова SQL! А если быть точнее PL/pgSQL, сегодня поговорим именно об этом расширение языка SQL, а конкретней о том, как использовать курсор при написании функции в СУБД PostgreSQL. И о том, для чего вообще нужны курсоры, и когда их лучше использовать.

Надеюсь, Вы не забыли все те примеры и уроки, которые мы рассматривали ранее, так как для прочтения этой статьи необходимы минимальные знания SQL, для того чтобы Вы вспомнили, вот эти материалы: Как написать функцию на PL/pgSQL, Написание табличной функции на PL/pgSQL — функция, которая возвращает таблицу в последней, кстати, уже затрагивалась тема курсоров, но не подробно, поэтому сегодня мы поговорим о курсорах уже подробней.

Что такое курсор в SQL?

Курсор в SQL – это временная выборка записей в процессе выполнения функции, над которой могут выполняться необходимые Вам действия, данная выборка является указателем на область памяти.

Курсоры могут быть очень полезны, например, если Вам в функции необходимо выполнять определенные действия с каким то набором строк, при этом до начала выполнения функции Вы даже не знаете, сколько строк будет при обработке той или иной записи. Если проще курсор — это просто запрос, который запускается в процессе выполнения функции.

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

О том, что курсоры могут быть полезны, мы поговорили, но когда их лучше использовать? А использовать их лучше всего только тогда, когда у Вас нет другого выхода! Потому что курсор является очень ресурсоемким решением. В принципе если Вы будете выполнять операции над небольшим количеством записей, то это приемлемо, а если необходимо обработать большой объем данных, то Вы можете очень долго ждать, пока будет выполняться Ваша функция, а как Вы знаете быстрота в нашем деле чуть ли не главный фактор.

Пример использования курсора в функции на PL/pgSQL

О теории мы поговорили пора переходить к практике, и для начала общий синтаксис курсора в функции.

   
   CREATE OR REPLACE FUNCTION название функции(типы переменных)
    RETURNS тип возвращаемого значения  AS
  $BODY$
   DECLARE
        объявление переменных
        объявление курсора
   BEGIN
     открытие курсора
        перебор данных и операции над ними
     закрытие курсора
     RETURN возвращение значения;
   END;
   $BODY$
     LANGUAGE 'plpgsql' VOLATILE


Теперь давайте приведем рабочий пример использования курсора, т.е. напишем функцию, в которой мы будем использовать курсор.

Примечание! Данный пример не из жизни, он смоделирован мной, поэтому у Вас такой ситуации может и не возникнуть.

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

Пример таблицы с несколькими записями:

id_per id_user rashod summa pr
1 1 100 100 0
1 2 100 110 0
2 1 100 90 0
2 2 100 90 0
3 1 110 100 0
3 2 100 100 10

где,

  • id_per – период по которому идет отчет;
  • id_user – идентификатор сотрудника;
  • rashod – сумма расходов за этот период;
  • summa – сумма, которая выделялась на расходы;
  • pr – возможная премия, на погашение задолженности в прошлом периоде.

Стоит следующая задача, нам необходимо определить тот период у сотрудников, в котором они расходовали средств больше, чем им выдали, и потом не возместили. При условии, что в следующем месяце им могут возместить этот расход (колонка pr), а могут и не возместить.

Т.е. в нашем примере у сотрудника с id_user = 1, этот период будет с id_per = 2, а у сотрудника с id_user = 2, этот период будет с id_per = 3. Другими словами, во втором периоде они оба перерасходовали выданные им средства, но сотруднику с id_user = 2 в следующем месяце их возместили, а с id_user = 1 нет, поэтому первый период возникновения перерасхода (причем не погашенного) у сотрудника с id_user = 1 будет именно период с id_per = 2.

В общем как то так:). Но для нас главное научиться использовать курсор в функциях, и наша функция будет выглядеть вот так.

Схема в базе PostgreSQL называется test и таблица тоже называется test, а функцию я назвал test.my_fun(numeric). Numeric – это как Вы помните тип входящего параметра.

   
   CREATE OR REPLACE FUNCTION test.my_fun(numeric)
     RETURNS numeric  AS
   $BODY$
   DECLARE
        _id_user ALIAS FOR $1;
        --объявляем курсор
        crs_my CURSOR FOR select id_per, rashod, summa from test.
test where id_user = _id_user order by id_per; --объявляем нужные нам переменные _id_per numeric; _rashod numeric; _summa numeric; _pr numeric; _var numeric; _rezult numeric; BEGIN _pr:=0; OPEN crs_my;--открываем курсор LOOP --начинаем цикл по курсору --извлекаем данные из строки и записываем их в переменные FETCH crs_my INTO _id_per, _rashod, _summa; --если такого периода и не возникнет, то мы выходим IF NOT FOUND THEN EXIT;END IF; --ищем сумму возмещения, если она была select into _pr pr from test.test where id_user=_id_user and id_per = _id_per+1; _var = _rashod - _summa; if _var > 0 then _var = _var - _pr; End if; _rezult=_id_per; --если _var даже после возмещения больше нуля, то выходим и возвращаем период EXIT when _var > 0; END LOOP;--заканчиваем цикл по курсору CLOSE crs_my; --закрываем курсор RETURN _rezult;--возвращаем результат END; $BODY$ LANGUAGE 'plpgsql' VOLATILE

В функции я все прокомментировал, надеюсь понятно. Главное здесь это наш курсор crs_my, затем мы просто открываем его, извлекаем данные с помощью FETCH по каждой строке наших данных и делаем это с помощью цикла LOOP. Есть один нюанс, когда будете писать запрос для курсора, в Ваших функциях, то учитывайте сортировку, потому что цикл работает с первой строки записи, и если необходимо изменить порядок извлечения данных, то делайте это в запросе, который используется в курсоре.

Использовать функцию можно вот так:

   
   SELECT test.my_fun(1)


Результат, как Вы помните, будет 2.

Если хотите запустить по всем записям, то используйте вот такой запрос:

   
   SELECT test.my_fun(id_user) FROM test.test


Заметка! Для комплексного изучения языка SQL рекомендую почитать мою книгу «SQL код». Данный книга рассчитана на изучение языка SQL как стандарта, т.е. на изучение тех возможностей SQL, которые доступны и точно будут работать во всех популярных системах управления базами данных (СУБД).

Вот такой простой пример! Надеюсь, курсоры Вам как-то помогут в ваших функциях, но снова напомню, злоупотреблять курсорами не следует, а использовать их нужно только по необходимости. Удачи!

Нравится1Не нравится

T-SQL синтаксис курсоров

T-SQL синтаксис курсоров


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

Таблица 13.2. Синтаксис Transact-SQL для работы с курсорами


Команда или функция

Предназначение

DECLARE CURSOR

Объявляет курсор

OPEN

Открывает курсор, чтобы можно было получать из него данные

FETCH

Выбирает одну запись из курсора

CLOSE

Закрывает курсор, оставляя внутренние структуры, связанные с ним

DEALLOCATE

Освобождает внутренние структуры курсора

@@CURSOR_ROWS

Возвращает количество записей в курсоре

@@FETCH_STATUS

Определяет, была ли удачна или неудачна последняя команда FETCH

CURSOR_STATUS()

Возвращает информацию о статусе курсора или курсорной переменной

DECLARE CURSOR


DECLARE CURSOR объявляет курсор.
Есть две основные версии команды DECLARE CURSOR — совместимый с ANSI /ISO SQL 92 синтаксис и расширенный синтаксис Transact-SQL. Синтаксис ANSI /ISO выглядит так:

DECLARE name [INSENSITIVE][SCROLL] CURSOR

FOR select

[FOR {READ ONLY | UPDATE [OF column [,...n]]}]

А расширенный синтаксис Transact-SQL так:

DECLARE name CURSOR

[LOCAL | GLOBAL]

[FORWARD_ONLY | SCROLL]

[STATIC | KEYSET | DYNAMIC | FAST_FORWARD]

[READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]

[TYPE_WARNING]

FOR select

[FOR {READ ONLY | UPDATE [OF column [,...n]]}]

Компонента select команды — это обыкновенный оператор SELECT, который определяет, какие записи возвращает курсор. В нем нельзя использовать ключевые слова COMPUTE [BY], FOR BROWSE или INTO. Компонента select влияет на то, будет ли курсор открыт только для чтения. Например, если вы включите предложение FOR UPDATE, но укажете select, которая по существу запрещает изменения (например, включает GROUP BY или DISTINCT), ваш курсор будет неявно преобразован в курсор только для чтения (или статический).

Сервер преобразует курсоры к статическим, не обновляемым по своей сути. Этот тип автоматического преобразования известен как неявное преобразование курсоров (implicit cursor conversions). Существует несколько критериев, которые влияют на неявное преобразование курсоров; за более подробной информацией обратитесь к Books Online. Для возможности изменения курсора вы не обязаны указывать FOR UPDATE явно, если сам по себе запрос SELECT является изменяемым. И еще раз, если не указано иначе, то будет ли курсор изменяемым, определяется характеристиками оператора SELECT. Вот пример:

CREATE TABLE #temp (k1 int identity, c1 int NULL)

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

DECLARE c CURSOR

FOR SELECT k1, c1 FROM #temp

OPEN c

FETCH c

UPDATE #temp

SET c1=2

WHERE CURRENT OF c

SELECT * FROM #temp

CLOSE c

DEALLOCATE c

GO

DROP TABLE #temp

k1 c1

----------- -----------

1 NULL

k1 c1

----------- -----------

1 2

2 NULL

3 NULL

4 NULL

Даже притом, что курсор не объявлен как изменяемый, он является изменяемым на основании того факта, что его оператор SELECT изменяемый — то есть сервер может преобразовать изменение курсора в изменение соответствующей записи таблицы. Если вы укажете предложение FOR UPDATE и включите список столбцов, то столбцы, которые вы изменяете, должны быть указаны в этом списке. Если вы попытаетесь изменить столбец, которого нет в списке с помощью предложения WHERE CURRENT OF оператора UPDATE, SQL Server отклонит изменения и сгенерирует сообщение об ошибке. Вот пример:

CREATE TABLE #temp (k1 int identity, c1 int NULL, c2 int NULL)

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

DECLARE c CURSOR

FOR SELECT k1, c1, c2 FROM #temp

FOR UPDATE OF c1

OPEN c

FETCH c

-- Плохой T-SQL -- Этот UPDATE пытается изменить столбец, которого нет в списке FOR UPDATE OF

UPDATE #temp

SET c2=2

WHERE CURRENT OF c

k1 c1 c2

---------- ------------ ---------------

1 NULL NULL

Server: Msg 16932, Level 16, State 1, Line 18

The cursor has a FOR UPDATE list and the requested column to be updated is not

in this list.

The statement has been terminated.

Если select ссылается на переменную, переменная вычисляется, когда курсор объявляется, а не когда открывается. Это существенно, так как вы должны присваивать значения переменным до объявления курсора, который их использует. Вы не можете сначала объявить курсор, затем присвоить значение переменной, от которой он зависит, и рассчитывать, что курсор будет работать правильно. Вот пример:

-- В случае, если курсор остался от предыдущего примера

DEALLOCATE c

DROP TABLE #temp

GO

CREATE TABLE #temp (k1 int identity, c1 int NULL)

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

DECLARE @k1 int

DECLARE c CURSOR

FOR SELECT k1, c1 FROM #temp WHERE k1<@k1 -- Не будет работать -- @k1 здесь равно NULL

SET @k1=3 -- Это надо переместить перед DECLARE CURSOR

OPEN c

FETCH c

UPDATE #temp

SET c1=2

WHERE CURRENT OF c

SELECT * FROM #temp

CLOSE c

DEALLOCATE c

GO

DROP TABLE #temp

k1 c1

----------- -----------

Server: Msg 16930, Level 16, State 1, Line 18

The requested row is not in the fetch buffer.

The statement has been terminated.

k1 c1

----------- -----------

1 NULL

2 NULL

3 NULL

4 NULL

Глобальные и локальные курсоры

Глобальные курсоры видимы вне пакета, хранимой процедуры или триггера, создавшего его, и существуют до тех пор, пока явно не будут освобождены или пока соединение, создавшее его. Локальный курсор видим только программному модулю, который его создал, если только курсор не возвращен с помощью выходного параметра. Локальные курсоры неявно освобождаются, когда выходят из области видимости. Для совместимости с предыдущими версиями, SQL Server по умолчанию создает глобальные курсоры, но вы можете отменить поведение по умолчанию, явно указав ключевое слово GLOBAL или LOCAL, когда объявляете курсор. Заметьте, что вы можете иметь глобальные и локальные курсоры с одинаковыми именами, хотя это довольно сомнительная практика кодирования. Например, этот код выполняется без ошибки:

DECLARE Darryl CURSOR -- My brother Darryl

LOCAL

FOR SELECT stor_id, title_id, qty FROM sales

DECLARE Darryl CURSOR -- My other brother Darryl

GLOBAL

FOR SELECT au_lname, au_fname FROM authors

OPEN GLOBAL Darryl

OPEN Darryl

FETCH GLOBAL Darryl

FETCH Darryl

CLOSE GLOBAL Darryl

CLOSE Darryl

DEALLOCATE GLOBAL Darryl

DEALLOCATE Darryl

au_lname au_fname

---------------------------------------- --------------------

White Johnson

stor_id title_id qty

---------- ------------ ---------

6380 BU1032 5

Мы можете изменить, будет ли SQL Server создавать глобальные курсоры, если не указана область видимости, с помощью системной хранимой процедуры sp_dboption (смотрите следующий раздел «Конфигурирование курсоров» за более подробной информацией).

OPEN


OPEN делает записи курсора доступными с помощью FETCH. Если курсор INSENSITIVE или STATIC, OPEN копирует все результирующее множество во временную таблицу. Если это KEYSET-курсор, OPEN копирует множество уникальных значений (или все множество потенциальных ключей, если не существует уникального ключа) во временную таблицу. В OPEN можно указать область видимости курсора, если включить опциональное ключевое слово GLOBAL. Если существуют и локальный и глобальный курсор с одинаковым именем (вы должны по возможности избегать этого), применяйте GLOBAL, чтобы указать курсор, который вы хотите открыть. (Опция базы данных default to local cursor определяет, получите ли вы глобальный или локальный курсор, когда ни то, ни другое явно не указано. Для более подробной информации смотрите следующий раздел, посвященный конфигурированию курсоров).

Используйте автоматическую переменную @@CURSOR_ROWS, чтобы определить, сколько записей в курсоре. Вот простой пример OPEN:

CREATE TABLE #temp (k1 int identity PRIMARY KEY, c1 int NULL)

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

DECLARE GlobalCursor CURSOR STATIC -- Объявляем глобальный курсор

GLOBAL

FOR SELECT k1, c1 FROM #temp

DECLARE LocalCursor CURSOR STATIC -- Объявляем локальный курсор

LOCAL

FOR SELECT k1, c1 FROM #temp WHERE k1<4 -- Возвращает только три записи

OPEN GLOBAL GlobalCursor

SELECT @@CURSOR_ROWS AS NumberOfGLOBALCursorRows

OPEN LocalCursor

SELECT @@CURSOR_ROWS AS NumberOfLOCALCursorRows

CLOSE GLOBAL GlobalCursor

DEALLOCATE GLOBAL GlobalCursor

CLOSE LocalCursor

DEALLOCATE LocalCursor

GO

DROP TABLE #temp

NumberOfGLOBALCursorRows

------------------------

4

NumberOfLOCALCursorRows

-----------------------

3

Для динамических курсоров @@CURSOR_ROWS возвращает –1, так как добавление новых записей может в любое время изменить количество записей, возвращенных курсором. Если курсор заполняется асинхронно, (смотрите раздел «Конфигурирование курсоров»), @@CURSOR_ROWS возвращает отрицательное значение, абсолютное значение которого показывает, сколько записей в настоящий момент в курсоре.

FETCH


FETCH — способ, с помощью которого вы получаете данные из курсора. Можете считать его специальным оператором SELECT, который возвращает только одну запись из предопределенного результирующего множества. Обычно FETCH вызывается в цикле, который использует @@FETCH_STATUS в качестве контролирующей переменной, каждый удачный вызов FETCH возвращает следующую запись курсора.

Курсоры с возможностью прокрутки (DYNAMIC, STATIC и KEYSET-курсоры, или те, которые объявлены с опцией SCROLL) позволяют FETCH получать не только следующие записи курсора. В дополнение к получению следующей записи прокручиваемые курсоры позволяют с помощью FETCH получить предыдущую запись, первую запись, последнюю запись, запись по ее номеру, и запись относительно текущей. Вот простой пример:

SET NOCOUNT ON

CREATE TABLE #cursortest (k1 int identity)

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

DECLARE c CURSOR SCROLL

FOR SELECT * FROM #cursortest

OPEN c

FETCH c -- Получаем первую запись

FETCH ABSOLUTE 4 FROM c -- Получаем 4-ю запись

FETCH RELATIVE -1 FROM c – Получаем 3-ю запись

FETCH LAST FROM c -- Получаем последнюю запись

FETCH FIRST FROM c -- Получаем первую запись

CLOSE c

DEALLOCATE c

GO

DROP TABLE #cursortest

k1

-----------

1

k1

-----------

4

k1

-----------

3

k1

-----------

10

k1

-----------

1

FETCH можно использовать для получения результирующего множества, но обычно эта команда служит для заполнения локальных переменных данными из таблицы. Предложение INTO команды FETCH позволяет присваивать полученные значения локальным переменным. Вот пример:

SET NOCOUNT ON

CREATE TABLE #cursortest (k1 int identity)

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

INSERT #cursortest DEFAULT VALUES

DECLARE c CURSOR SCROLL

FOR SELECT * FROM #cursortest

DECLARE @k int

OPEN c

FETCH c INTO @k

WHILE (@@FETCH_STATUS=0) BEGIN

SELECT @k

FETCH c INTO @k

END

CLOSE c

DEALLOCATE c

GO

DROP TABLE #cursortest

-----------

1

-----------

2

-----------

3

-----------

4

-----------

5

-----------

6

-----------

7

-----------

8

-----------

9

-----------

10

NEXT — операция для выбора по умолчанию, так что, если вы не укажете какой тип выбора вам нужен, вы получите следующую запись курсора. Для операций выбора, отличных от NEXT, ключевое слово FROM является обязательным.

FETCH RELATIVE 0 можно использовать для обновления текущей записи. Это позволяет учитывать изменения текущей записи при прохождении курсора. Вот пример:

USE pubs

SET CURSOR_CLOSE_ON_COMMIT OFF -- На тот случай, если было включено

SET NOCOUNT ON

DECLARE c CURSOR SCROLL

FOR SELECT title_id, qty FROM sales ORDER BY qty

OPEN c

BEGIN TRAN -- Чтобы можно было отменить наши имзменения

PRINT 'Before image'

FETCH c

UPDATE sales

SET qty=4

WHERE qty=3 -- Мы знаем, что этому соответствует только одна запись, первая

PRINT 'After image'

FETCH RELATIVE 0 FROM c

ROLLBACK TRAN -- Отменяем UPDATE

CLOSE c

DEALLOCATE c

Before image

title_id qty

-------- ------

PS2091 3

After image

title_id qty

-------- ------

PS2091 4

CLOSE


CLOSE освобождает текущее результирующее множество курсора, и снимает любые блокировки, наложенные курсором. (До версии 7.0, SQL Server оставлял все блокировки до окончания транзакции, включая блокировки курсоров. Начиная с версии 7.0, блокировки курсоров обрабатываются независимо от других типов блокировок). Структуры данных курсора остаются нетронутыми, так что если понадобится, курсор можно открыть снова. Для закрытия глобального курсора указывайте ключевое слово GLOBAL.

DEALLOCATE


После того, как вы закончили работу с курсором, необходимо освободить его. Курсор занимает место в процедурном кэше, которое можно использовать для других целей, если оно вам больше не нужно. Даже при том, что освобождение курсора автоматически закрывает его, считается плохим тоном освобождение курсора без предварительного его закрытия с помощью команды CLOSE.

Конфигурирование курсоров


В дополнение к конфигурированию курсоров с помощью опций при объявлении, Transact-SQL предоставляет команды и опции конфигурации, которые также могут изменять поведение курсоров. Процедуры sp_configure и sp_dboption, команда SET могут быть использованы для конфигурирования того, как курсоры создаются и как они себя ведут, после того как созданы.

Асинхронные курсоры


По умолчанию, SQL Server генерирует все наборы ключевых значений синхронно — то есть вызов OPEN не закончится, пока результирующее множество курсора не будет полностью создано. Это может быть неоптимально для больших множеств, и вы можете изменить это поведение с помощью опции конфигурации sp_configure ‘cursor threshold’ (cursor threshold является дополнительной опцией; включите дополнительные опции с помощью sp_configure ‘show advanced options’, чтобы получить к ней доступ). Вот пример, который показывает отличия использования асинхронного курсора:

-- Включаем дополнительные опции, чтобы можно было изменить 'cursor threshold'

EXEC sp_configure 'show advanced options',1

RECONFIGURE WITH OVERRIDE

USE northwind

DECLARE c CURSOR STATIC -- Заставляем записи копироваться в tempdb

FOR SELECT OrderID, ProductID FROM [Order Details]

DECLARE @start datetime

SET @start=getdate()

-- Сначала попробуем с помощью синхронного курсора

OPEN c

PRINT CHAR(13) -- Для красивого вывода

SELECT DATEDIFF(ms,@start,getdate()) AS [Milliseconds elapsed for Synchronous cursor]

SELECT @@CURSOR_ROWS AS [Number of rows in Synchronous cursor]

CLOSE c

-- Теперь изменим 'cursor threshold', чтобы заставить сервер использовать асинхронные курсоры

EXEC sp_configure 'cursor threshold', 1000 -- Асинхронно для курсоров, в которых > 1000 записей

RECONFIGURE WITH OVERRIDE

PRINT CHAR(13) -- Для красивого вывода

SET @start=getdate()

OPEN c -- Открываем асинхронный курсор, так как в таблице больше 1000 записей

-- OPEN возвращается немедленно, так как курсор заполняется асинхронно

SELECT DATEDIFF(ms,@start,getdate()) AS [Milliseconds elapsed for Asynchronous cursor]

SELECT @@CURSOR_ROWS AS [Number of rows in Asynchronous cursor]

CLOSE c

DEALLOCATE c

GO

EXEC sp_configure 'cursor threshold', -1 -- Возвращаем синхронные курсоры

RECONFIGURE WITH OVERRIDE

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

Configuration option changed. Run the RECONFIGURE statement to install.

Milliseconds elapsed for Synchronous cursor

-------------------------------------------

70

Number of rows in Synchronous cursor

------------------------------------

2155

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

Configuration option changed. Run the RECONFIGURE statement to install.

Milliseconds elapsed for Asynchronous cursor

--------------------------------------------

0

Number of rows in Asynchronous cursor

-------------------------------------

-1

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

Configuration option changed. Run the RECONFIGURE statement to install.

ANSI/ISO автоматическое закрытие курсоров


Спецификация ANSI/ISO SQL-92 определяет, что курсоры должны автоматически закрываться при фиксации транзакции. В этом нет большого смысла для приложений, в которых курсоры используются очень часто (те, которые задействуют прокручиваемые формы, например), так что в этом смысле SQL Server не соответствует стандарту. По умолчанию, курсоры SQL Server остаются открытыми, пока не будут явно закрыты, или, пока соединение, создавшее их, не отсоединится. Чтобы заставить SQL Server закрывать курсоры при фиксации транзакции, используйте команду SET CURSOR_CLOSE_ON_COMMIT. Вот пример:

CREATE TABLE #temp (k1 int identity PRIMARY KEY, c1 int NULL)

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

INSERT #temp DEFAULT VALUES

DECLARE c CURSOR DYNAMIC

FOR SELECT k1, c1 FROM #temp

OPEN c

SET CURSOR_CLOSE_ON_COMMIT ON

BEGIN TRAN

UPDATE #temp

SET c1=2

WHERE k1=1

COMMIT TRAN

-- Эти FETCH'и будут неудачны, так как курсор закрыт командой COMMIT

FETCH c

FETCH LAST FROM c

-- Этот CLOSE будет неудачен, так курсор закрыт командой COMMIT

CLOSE c

DEALLOCATE c

GO

DROP TABLE #temp

SET CURSOR_CLOSE_ON_COMMIT OFF

Server: Msg 16917, Level 16, State 2, Line 0

Cursor is not open.

Server: Msg 16917, Level 16, State 2, Line 26

Cursor is not open.

Server: Msg 16917, Level 16, State 1, Line 29

Cursor is not open.

Вопреки Books Online, откат транзакции не закрывает изменяемые курсоры, когда CLOSE_CURSOR_ON_COMMIT отключена. Фактическое поведение ROLLBACK значительно отличается от описанного в документации и больше соответствует тому, которое происходит при фиксации транзакции. В общем, ROLLBACK не закрывает курсоры, если только не была включена опция CLOSE_CURSOR_ON_COMMIT. Вот пример:

USE pubs

SET CURSOR_CLOSE_ON_COMMIT ON

BEGIN TRAN

DECLARE c CURSOR DYNAMIC

FOR SELECT qty FROM sales

OPEN c

FETCH c

UPDATE sales

SET qty=qty+1

WHERE CURRENT OF c

ROLLBACK TRAN

-- Эти команды FETCH будут неудачны, так как курсор был закрыт командой ROLLBACK

FETCH c

FETCH LAST FROM c

-- Эта команда CLOSE будет неудачна, так как курсор был закрыт командой ROLLBACK

CLOSE c

DEALLOCATE c

GO

SET CURSOR_CLOSE_ON_COMMIT OFF

qty

------

5

Server: Msg 16917, Level 16, State 2, Line 21

Cursor is not open.

Server: Msg 16917, Level 16, State 2, Line 22

Cursor is not open.

Server: Msg 16917, Level 16, State 1, Line 25

Cursor is not open.

Теперь давайте отключим CURSOR_CLOSE_ON_COMMIT и снова выполним запрос:

SET CURSOR_CLOSE_ON_COMMIT OFF

BEGIN TRAN

DECLARE c CURSOR DYNAMIC

FOR SELECT qty FROM sales

OPEN c

FETCH c

UPDATE sales

SET qty=qty+1

WHERE CURRENT OF c

ROLLBACK TRAN

-- Эти команды FETCH выполнятся, так как курсор был оставлен открытым несмотря на ROLLBACK

FETCH c

FETCH LAST FROM c

-- Эта команда CLOSE выполнится, поскольку курсор был оставлен открытым, несмотря на ROLLBACK

CLOSE c

DEALLOCATE c

qty

------

5

qty

------

3

qty

------

30

Несмотря на тот факт, что транзакция былаотменена, в то время как наш динамический курсор был открыт, это не повлияло на курсор. Это противоречит поведению сервера, описанному в документации.

Конфигурирование создания по умолчанию глобальных или локальных курсоров


SQL Server по умолчанию создает глобальные курсоры. Это делается для совместимости с предыдущими версиями сервера, которые не поддерживали локальные курсоры. Если вам необходимо это изменить, установите опцию базы данных default to local cursor database в true с помощью sp_dboption.

Модифицируемые курсоры


Предложения WHERE CURRENT OF команд UPDATE и DELETE позволяют модифицировать и удалять записи с помощью курсора. Модификация или удаление с помощью курсора известны как позиционная модификация. Вот пример:

USE pubs

SET CURSOR_CLOSE_ON_COMMIT OFF

SET NOCOUNT ON

DECLARE C CURSOR DYNAMIC

FOR SELECT * FROM sales

OPEN c

FETCH c

BEGIN TRAN -- Начинает транзакцию, чтобы можно было отменить наши изменения

-- Позиционный UPDATE

UPDATE sales SET qty=qty+1 WHERE CURRENT OF c

FETCH RELATIVE 0 FROM c

FETCH c

-- Позиционный DELETE

DELETE sales WHERE CURRENT OF c

SELECT * FROM sales WHERE qty=3

ROLLBACK TRAN -- Отменяем наши изменения

SELECT * FROM sales WHERE qty=3 -- Удаленные записи восстанавливаются

CLOSE c

DEALLOCATE c

stor_id ord_num ord_date qty payterms title_id

-------- ----------- --------------------------------- ----- ------------- -----------

6380 6871 1994-09-14 00:00:00. 000 5 Net 60 BU1032

stor_id ord_num ord_date qty payterms title_id

-------- ----------- --------------------------------- ----- ------------- -----------

6380 6871 1994-09-14 00:00:00.000 6 Net 60 BU1032

stor_id ord_num ord_date qty payterms title_id

-------- ----------- --------------------------------- ----- ------------- -----------

6380 722a 1994-09-13 00:00:00.000 3 Net 60 PS2091

stor_id ord_num ord_date qty payterms title_id

-------- ----------- --------------------------------- ----- ------------- -----------

stor_id ord_num ord_date qty payterms title_id

-------- ----------- --------------------------------- ----- ------------- -----------

6380 722a 1994-09-13 00:00:00.000 3 Net 60 PS2091

Курсорные переменные


Transact-SQL позволяет определять переменные, которые содержат указатели на курсоры, с помощью типа данных cursor. В командах OPEN, FETCH, CLOSE и DEALLOCATE можно использовать курсорные переменные, также как имена курсоров. Вы можете создавать переменные в хранимых процедурах, в которых заданы описания курсоров, и возвращать курсоры, созданные в хранимой процедуре, с помощью выходных параметров. Несколько процедур самого SQL Server используют эту возможность, чтобы возвращать результаты эффективным модульным способом (например, sp_cursor_list, sp_describe_cursor, sp_fulltext_tables_cursor). Заметьте, что вы не можете передавать курсор в процедуру с помощью входного параметра — вы можете только возвращать курсоры с помощью выходных параметров. Также нельзя определять столбцы таблицы курсорного типа — разрешены только переменные — также вы не можете присваивать значение курсорной переменной с помощью оператора SELECT (как в случае скалярных переменных) — для этого вы должны задействовать SET.

Выходные параметры типа cursor представляют собой усовершенствование по сравнению с традиционными результирующими множествами, поскольку дают вызывающей стороне больше контроля над обработкой записей, которые возвращает процедура. Вы можете обрабатывать курсоры сразу же, если хотите — обрабатывая их как обычное результирующее множество — или оставить его для дальнейшего использования. До изобретения курсорных переменных единственным способом достижения такой гибкости было сохранение результатов хранимой процедуры в таблицу с последующей ее обработкой. Это хорошо работает с простыми, небольшими результирующими множествами, но может быть проблематично для больших.

Вы можете использовать функцию CURSOR_STATUS(), чтобы проверить, ссылается ли выходной курсорный параметр на открытый курсор и чтобы определить, сколько записей в нем находится. Вот пример, который показывает использование курсорных переменных, выходных параметров и функцию CURSOR_STATUS():

CREATE PROC listsales_cur @title_id tid, @salescursor cursor varying OUT

AS

-- Объявляем локальный курсор, чтобы он был автоматически особожден

-- когда выйдет из области видимости

DECLARE c CURSOR DYNAMIC

LOCAL

FOR SELECT * FROM sales WHERE title_id LIKE @title_id

DECLARE @sc cursor -- Локальная курсорная переменная

SET @sc=c -- Теперь у нас есть две ссылки на курсор

OPEN c

FETCH @sc

SET @[email protected] -- Возвращаем курсор с помощью выходного параметра

RETURN 0

GO

SET NOCOUNT ON

-- Объявляем локальную курсорную переменную для получения выходного параметра

DECLARE @mycursor cursor

EXEC listsales_cur 'BU1032', @mycursor OUT -- Вызываем процедуру

-- Убедимся, что курсор открыт и в нем есть по крайне мере одна запись

IF (CURSOR_STATUS('variable','@mycursor')=1) BEGIN

FETCH @mycursor

WHILE (@@FETCH_STATUS=0) BEGIN

FETCH @mycursor

END

END

CLOSE @mycursor

DEALLOCATE @mycursor

stor_id ord_num ord_date qty payterms title_id

-------- -------------- ---------------------------------- ----- --------------- -----------

6380 6871 1994-09-14 00:00:00. 000 5 Net 60 BU1032

stor_id ord_num ord_date qty payterms title_id

-------- -------------- --------------------------------- ----- ---------------- -------

8042 423LL930 1994-09-14 00:00:00.000 10 ON invoice BU1032

stor_id ord_num ord_date qty payterms title_id

-------- ------------ --------------------------------- ----- ------------- -----------

8042 QA879.1 1999-06-24 19:13:26.230 30 Net 30 BU1032

stor_id ord_num ord_date qty payterms title_id

-------- ----------- --------------------------------- ----- ------------- -----------

Обратите внимание на то, как этот код ссылается на курсор с помощью трех различных переменных, а также имени курсора. Для каждой команды, за исключением DEALLOCATE, ссылка на курсор с помощью курсорной переменной — аналог ссылки на курсор по имени. Если вы открываете курсор с помощью команды OPEN, независимо от того, ссылаетесь вы на курсор по имени или с помощью курсорной переменной, курсор будет открыт, и вы можете выбирать из него записи с помощью команды FETCH, используя любую переменную, которая ссылается на него. DEALLOCATE отличается в том смысле, что эта команда на самом деле не освобождает курсор, если только это не последняя ссылка на него. Это, однако, действительно предотвращает доступ к нему с помощью указанного идентификатора. Так что если у вас есть курсор с именем foo и курсорная переменная с названием foovar, которой было присвоено значение foo, освобождение foo лишь запретит доступ к курсору с помощью foo — foovar останется неизменной.

Хранимые процедуры для работы с курсорами


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

Таблица 13.3. Хранимые процедуры, связанные с триггерами


Процедура

Выполняемые функции

sp_cursor_list

Возвращает список курсоров, открытых соединением, а также их атрибуты

sp_describe_cursor

Возвращает атрибуты отдельного курсора

sp_describe_cursor_columns

Возвращает столбцы курсора (и их атрибуты)

sp_describe_cursor_tables

Возвращает список таблиц, использованных в курсоре

Оптимизация производительности курсоров


Лучший способ оптимизации курсоров — вообще не использовать их, когда это возможно. Как я уже говорил, SQL Server лучше работает с множествами данных, чем с отдельными записями. Он представляет собой реляционную СУБД, а работа с отдельными записями никогда не была сильно стороной реляционных СУБД. Хотя иногда без курсоров не обойтись, так что вот несколько советов по их оптимизации:

  • Не используйте статические/нечувствительные курсоры без необходимости. При открытии статического курсора все его записи копируются во временную таблицу. Вот почему они нечувствительны к изменениям — он на самом деле ссылается на копию таблицы в tempdb. Естественно, чем больше результирующее множество, тем более вероятно, что использование статического курсора вызовет проблемы с ресурсами в tempdb.

  • Используйте keyset-курсоры, если только они вам действительно необходимы. Как и в случае статических курсоров, открытие keyset-курсора создает временную таблицу. Хотя эта таблица содержит только значения ключей основной таблицы (если, конечно, существует уникальный ключ), она может все равно иметь существенный размер при работе с большими результирующими множествами.

  • Используйте опцию FAST_FORWARD вместо FORWARD_ONLY при работе с однонаправленными множествами только для чтения. При использовании FAST_FORWARD объявляется FORWARD_ONLY, READ_ONLY курсор с некоторыми внутренними оптимизациями производительности.

  • Объявляйте курсоры только для чтения с помощью ключевого слова READ_ONLY. Это препятствует случайным изменениям, кроме того, сервер будет знать, что курсор не изменит записи, по которым проходит.

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

  • Будьте осторожны с модифицируемыми динамическими курсорами, особенно с теми, которые созданы по таблицам с неуникальными кластерными индексами, так как они могут вызвать «проблему Хэллоуина» —повторные, ошибочные обновления одной и той же строки или строк. Так как SQL Server внутренне делает неуникальные ключи кластерных индексов уникальными, добавляя к ним порядковый номер, возможно, что вы измените значение ключа записи на такое, которое уже существует и заставите сервер добавить суффикс, из-за которого запись переместится дальше в результирующем множестве. При выборе оставшегося результирующего множества вы опять наткнетесь на эту запись, и процесс повторится, что приведет к бесконечному циклу. Вот пример, иллюстрирующий данную проблему:

-- Этот код создает курсор, который представляет Проблему Хэллоуина.

-- Не запускайте его, если только вам не нравятся бесконечные циклы.

SET NOCOUNT ON

CREATE TABLE #temp (k1 int identity, c1 int NULL)

CREATE CLUSTERED INDEX c1 ON #temp(c1)

INSERT #temp VALUES (8)

INSERT #temp VALUES (6)

INSERT #temp VALUES (7)

INSERT #temp VALUES (5)

INSERT #temp VALUES (3)

INSERT #temp VALUES (0)

INSERT #temp VALUES (9)

DECLARE c CURSOR DYNAMIC

FOR SELECT k1, c1 FROM #temp

OPEN c

FETCH c

WHILE (@@FETCH_STATUS=0) BEGIN

UPDATE #temp

SET c1=c1+1

WHERE CURRENT OF c

FETCH c

SELECT * FROM #temp ORDER BY k1

END

CLOSE c

DEALLOCATE c

GO

DROP TABLE #temp


  • Используйте асинхронные курсоры при работе с большими множествами, чтобы возвращать управление вызывающей стороне как можно быстрее. Асинхронные курсоры особенно полезны при возвращении результирующего множества значительного размера прокручиваемой форме, так как они позволяют приложению начать отображение практически немедленно.

Заключение


Курсоры —о не лучший способ решения большинства задач, они могут вызывать серьезные проблемы с производительностью, если их неправильно использовать.

НОУ ИНТУИТ | Лекция | Курсоры: принципы работы

Аннотация: Дается определение курсора. Приводится описание его типов и поведения: статические, динамические, последовательные и ключевые курсоры. Описываются принципы управления курсором: создание и открытие курсора, считывание данных, закрытие курсора. Приводятся примеры программирования курсора.

Понятие курсора

Запрос к реляционной базе данных обычно возвращает несколько рядов (записей) данных, но приложение за один раз обрабатывает лишь одну запись. Даже если оно имеет дело одновременно с несколькими рядами (например, выводит данные в форме электронных таблиц), их количество по-прежнему ограничено. Кроме того, при модификации, удалении или добавлении данных рабочей единицей является ряд. В этой ситуации на первый план выступает концепция курсора, и в таком контексте курсор – указатель на ряд.

Курсор в SQL – это область в памяти базы данных, которая предназначена для хранения последнего оператора SQL. Если текущий оператор – запрос к базе данных, в памяти сохраняется и строка данных запроса, называемая текущим значением, или текущей строкой курсора. Указанная область в памяти поименована и доступна для прикладных программ.

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

В соответствии со стандартом SQL при работе с курсорами можно выделить следующие основные действия:

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

В разных реализациях определение курсора может иметь некоторые отличия. Так, например, иногда разработчик должен явным образом освободить выделяемую для курсора память. После освобождения курсора ассоциированная с ним память также освобождается. При этом становится возможным повторное использование его имени. В других реализациях при закрытии курсора освобождение памяти происходит неявным образом. Сразу после восстановления она становится доступной для других операций: открытие другого курсора и т.д.

В некоторых случаях применение курсора неизбежно. Однако по возможности этого следует избегать и работать со стандартными командами обработки данных: SELECT, UPDATE, INSERT, DELETE. Помимо того, что курсоры не позволяют проводить операции изменения над всем объемом данных, скорость выполнения операций обработки данных посредством курсора заметно ниже, чем у стандартных средств SQL.

Реализация курсоров в среде MS SQL Server

SQL Server поддерживает три вида курсоров:

  • курсоры SQL применяются в основном внутри триггеров, хранимых процедур и сценариев;
  • курсоры сервера действуют на сервере и реализуют программный интерфейс приложений для ODBC, OLE DB, DB_Library;
  • курсоры клиента реализуются на самом клиенте. Они выбирают весь результирующий набор строк из сервера и сохраняют его локально, что позволяет ускорить операции обработки данных за счет снижения потерь времени на выполнение сетевых операций.

Различные типы многопользовательских приложений требуют и различных типов организации параллельного доступа к данным. Некоторым приложениям необходим немедленный доступ к информации об изменениях в базе данных. Это характерно для систем резервирования билетов. В других случаях, например, в системах статистической отчетности, важна стабильность данных, ведь если они постоянно модифицируются, программы не смогут эффективно отображать информацию. Различным приложениям нужны разные реализации курсоров.

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

Курсоры делятся на две категории: последовательные и прокручиваемые. Последовательные позволяют выбирать данные только в одном направлении – от начала к концу. Прокручиваемые же курсоры предоставляют большую свободу действий – допускается перемещение в обоих направлениях и переход к произвольной строке результирующего набора курсора.Если программа способна модифицировать данные, на которые указывает курсор, он называется прокручиваемым и модифицируемым. Говоря о курсорах, не следует забывать об изолированности транзакций. Когда один пользователь модифицирует запись, другой читает ее при помощи собственного курсора, более того, он может модифицировать ту же запись, что делает необходимым соблюдение целостности данных.

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

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

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

В статический курсор внести изменения невозможно, поэтому он всегда открывается в режиме "только для чтения".

Динамический курсор поддерживает данные в "живом" состоянии, но это требует затрат сетевых и программных ресурсов. При использовании динамических курсоров не создается полная копия исходных данных, а выполняется динамическая выборка из исходных таблиц только при обращении пользователя к тем или иным данным. На время выборки сервер блокирует строки, а все изменения, вносимые пользователем в полный результирующий набор курсора, будут видны в курсоре. Однако если другой пользователь внес изменения уже после выборки данных курсором, то они не отразятся в курсоре .

Курсор, управляемый набором ключей, находится посередине между этими крайностями. Записи идентифицируются на момент выборки, и тем самым отслеживаются изменения . Такой тип курсора полезен при реализации прокрутки назад – тогда добавления и удаления рядов не видны, пока информация не обновится, а драйвер выбирает новую версию записи, если в нее были внесены изменения.

Последовательные курсоры не разрешают выполнять выборку данных в обратном направлении. Пользователь может выбирать строки только от начала к концу курсора . Последовательный курсор не хранит набор всех строк. Они считываются из базы данных, как только выбираются в курсоре, что позволяет динамически отражать все изменения, вносимые пользователями в базу данных с помощью команд INSERT, UPDATE, DELETE. В курсоре видно самое последнее состояние данных.

Статические курсоры обеспечивают стабильный взгляд на данные. Они хороши для систем "складирования" информации: приложений для систем отчетности или для статистических и аналитических целей. Кроме того, статический курсор лучше других справляется с выборкой большого количества данных. Напротив, в системах электронных покупок или резервирования билетов необходимо динамическое восприятие обновляемой информации по мере внесения изменений. В таких случаях используется динамический курсор. В этих приложениях объем передаваемых данных, как правило, невелик, а доступ к ним осуществляется на уровне рядов (отдельных записей). Групповой доступ встречается очень редко.

Курсоры (Cursors)

Курсор – это средство извлечения данных из базы данных Oracle. Курсоры содержат определения столбцов и объектов (таблиц, представлений и т.п.) из которых будут извлекаться данные, а также набор критериев, определяющих какие именно строки должны быть выбраны.

Пользователю доступны следующие способы выполнения запроса к базе данных:

  • Неявные курсоры - простой оператор SELECT ... INTO извлекает одну строку данных непосредственно в переменные локальной программы. Это удобный (и часто наиболее эффективный) способ доступа к данным, использование которого, однако, может приводить к необходимости повторного кодирования оператора SELECT (или похожих операторов) в нескольких местах программы.
  • Явные курсоры - вы можете явно объявить курсов в разделе объявлений (локального блока или пакета). В этом случае курсор можно будет открывать и извлекать данные в одной или нескольких программах, причем возможности контроля будут шире, чем при использовании неявных курсоров.
  • Курсорные переменные - дополнительный уровень гибкости обеспечивают курсорные переменные (объявленные на основе типа REF CURSOR), которые позволяют передавать указатель на результирующее множество, полученное по запросу из одной программы в другую. Любая программа, имеющая доступ к такой переменной, сможет открывать и закрывать курсор, а также выбирать из него данные.
  • Курсорные выражения - появившиеся в версии Oracle 9i выражения CURSOR преобразуют оператор SELECT в указатель (типа REF CURSOR) на результирующее множество и могут использоваться в сочетании с табличными функциями для повышения прозводительности приложений.

Сравнение явных и неявных курсоров

В PL/SQL неявные курсоры – это курсоры, которые определяются в момент выполнения.

DECLARE
V_date DATE;
BEGIN
SELECT order_date
INTO v_date
FROM orders
WHERE order_number = 100;
END;

Явный курсор – это курсор, который определяется до начала выполнения.

DECLARE
CURSOR curs_get_od
IS
SELECT order_date
FROM orders
WHERE order_number = 100;
V_date DATE;
BEGIN
OPEN cure_get_od;
FETCH curs_get_od
INTO v_date;
CLOSE curs_get_od;
END;

Ключевое преимущество явного курсора заключается в наличии у него атрибутов, облегчающих применение условных операторов.

Типичные операции над запросами

Для исполнения оператора SQL внутри программы PL/SQL выполняет одни и те же операции для всех типов курсоров. В одних случаях PL/SQL выполняет их автоматически, а в других (для явных курсоров) программисту необходимо написать соответствующий код.

  • Синтаксический анализ - первым этапом обработки оператора SQL является его синтаксический анализ, который проводится для проверки корректности оператора и определения плана его выполнения.
  • Связывание - это сопоставление значений из вашей программы (хост-переменных) заполнителям используемого оператора SQL. Для статического SQL такое связывание выполняет само ядро PL/SQL. Для динамического SQL программист, если он планирует использовать переменные связывания, должен явно запросить выполнение этой операции.
  • Открытие - при открытии курсора, переменные связывания используются для определения результирующего множества команды SQL. Указатель активной (текущей) строки устанавливается на первой строке. В некоторых случаях явное открытие курсора не требуется; ядро PL/SQL само выполняет эту операцию (например, для неявных курсоров или встроенного динамического SQL).
  • Исполнение - на этапе исполнения оператор выполняется внутри ядра SQL.
  • Выборка - при выполнении запроса команда FETCH извлекает следующую строку из результирующего множества курсора. При каждой выборке PL/SQL передвигает курсор вреперд на одну строку по результирующему множеству. При работе с явными курсорами следует помнить, что в случае, когда строк для извлечения больше нет, FETCH ничего не делает (не инициирует исключение).
  • Закрытие - на этом этапе курсор закрывается, освобождается используемая им память. После закрытия курсор уже не содержит результирующее множество. В некоторых случаях явное закрытие курсора не требуется, ядро PL/SQL само выполняет эту операцию (например, для неявных курсоров или встроенного динамического SQL

Повторное использование курсоров

Скомпилированная версия курсора может использоваться повторно во избежание расходов на разбор и повторную компиляцию.

Полный и частичный разбор

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

  • Проверка – курсор проверяется на соответствие синтаксическим правилам SQL, также проверяются объекты (таблицы и столбцы), на которые он ссылается.
  • Компиляция – курсор компилируется в исполняемый код и загружается в разделяемый пул сервера баз данных. Для определения местоположения курсора в разделяемом пуле используется его адрес.
  • Вычисление плана выполнения – оптимизатор по стоимости (cost-based optimizer - CBO) Oracle определяет наилучший для данного курсора план выполнения и присоединяет его к курсору.
  • Вычисление хеша – ASCII-значения всех символов курсора складываются и передаются в функцию хеширования. Эта функция рассчитывает значение, по которому курсор легко может быть найден при повторном обращении. Данное значение называется хеш-значением курсора.

Чтобы определить, может ли планируемый к выполнению курсор воспользоваться уже скомпилированной версией из разделяемого пула, Oracle применяет сложный алгоритм.

  • 1 Рассчитать сумму ASCII – значений всех символов курсора ( исключая переменные связывания).
  • 2 Применить алгоритм хеширования к полученной сумме.
  • 3 Проверить наличие в разделяемом пуле курсора с таким же значением хеша.
  • 4 Если такой курсор найден, он может быть использован повторно.

Атрибуты курсора SQL Server

Курсор SQL Server - это объект базы данных, который используется для обработки данных в наборе строка за строкой. В этой статье мы рассмотрим, как создать курсор и различные атрибуты, используемые при объявлении курсора.

Создание курсора

Ниже приведены шаги, необходимые для создания курсора.

  • Declare - объявляет курсор с именем и оператором select, который заполняет набор результатов
  • Открыть - открывает курсор и заполняет его, выполняя оператор выбора, указанный при объявлении курсора.
  • Fetch - для извлечения определенной строки из курсора на основе аргументов выборки, таких как NEXT, FIRST, LAST и т. Д.
  • Close - закрывает текущий набор результатов курсора SQL Server и может быть открыт повторно.
  • Deallocate - удаляет ссылку на курсор и освобождает все ресурсы, связанные с курсором.

Создадим образец таблицы, вставим несколько строк и выполним операции курсора над таблицей с разными атрибутами.

CREATE TABLE Test (id INT, Name VARCHAR (50))

INSERT INTO Test values ​​(1, 'John')

INSERT INTO Test values ​​(2, 'Mike')

Синтаксис для создания курсора с атрибутами по умолчанию.

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

DECLARE @id INT, @name VARCHAR (50)

DECLARE DefaultCursor CURSOR

FOR

SELECT id, name FROM Test

OPEN DefaultCursor FROM

имя

WHILE @@ FETCH_STATUS = 0

BEGIN

SELECT @id, @name

FETCH NEXT FROM DefaultCursor INTO @id, @name

END

DefaultCursor

По умолчанию область действия курсора определяется на основе значения Курсор по умолчанию на уровне базы данных.Чтобы проверить или изменить текущую настройку, перейдите к базе данных в SQL Server Management Studio, щелкните правой кнопкой мыши базу данных и выберите Properties . Щелкните Options. Вы можете видеть, что в данном случае текущая настройка - GLOBAL . Если вы хотите изменить область действия курсора SQL Server по умолчанию, щелкните раскрывающийся список, измените его на ЛОКАЛЬНЫЙ и щелкните ОК

Вы также можете изменить этот параметр с помощью T-SQL.Выполните приведенную ниже инструкцию, чтобы изменить настройку по умолчанию на LOCAL.

USE [master]

GO

ALTER DATABASE [SampleDatabase] SET CURSOR_DEFAULT LOCAL WITH NO_WAIT

GO

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

USE [master]

GO

ALTER DATABASE [SampleDatabase] SET CURSOR_DEFAULT GLOBAL WITH NO_WAIT

GO

МЕСТНОЕ

Если курсор создан с атрибутом LOCAL, то область действия курсора ограничена тем пакетом, хранимой процедурой или триггером, в которых был создан курсор.

Давайте попробуем объявить локальный курсор в одном пакете и открыть его в другом пакете.

DECLARE DefaultCursor CURSOR LOCAL

FOR

SELECT id, name FROM Test

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

Все операторы, ссылающиеся на имя курсора, должны идти в одном пакете, если курсор объявлен с локальным атрибутом.

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

DECLARE @id INT, @name VARCHAR (50)

DECLARE DefaultCursor CURSOR LOCAL

FOR

SELECT id, name FROM Test

OPEN 9Tursor по умолчанию id, @name

WHILE @@ FETCH_STATUS = 0

BEGIN

SELECT @id, @name

FETCH NEXT FROM DefaultCursor INTO @id, @name

END

CLS

ВЫКЛЮЧИТЬ Курсор по умолчанию

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

ВСЕГО

Если курсор создан с атрибутом GLOBAL, область действия курсора не ограничивается пакетом, в котором он был создан, и на имя курсора может ссылаться любой пакет в том же соединении.

Давайте объявим курсор SQL Server с глобальным атрибутом в одном пакете и попробуем использовать ссылку курсора в другом пакете.

DECLARE DefaultCursor CURSOR GLOBAL

FOR

SELECT id, name FROM Test

Теперь откроем курсор и получим текущую запись в другом пакете.

ОТКРЫТЬ DefaultCursor

FETCH NEXT FROM DefaultCursor

Мы должны выполнить команду DEALLOCATE для курсора, чтобы удалить ссылки курсора, иначе ссылки курсора будут удалены только при закрытии соединения.

ТОЛЬКО ВПЕРЕД

Когда курсор указан с помощью FORWARD_ONLY, его можно прокручивать от первой до последней строки, используя команду fetch next.Все остальные параметры выборки не поддерживаются. Все изменения данных, сделанные другими пользователями перед выборкой строки, видны.

Давайте создадим курсор FORWARD_ONLY и попробуем использовать другие параметры выборки, такие как «LAST» и «PRIOR». Это вызывает ошибку, как показано на изображении ниже.

Только опция FETCH NEXT поддерживается, когда курсор создается с FORWARD_ONLY.

СВИТОК

Когда курсор создается с атрибутом SCROLL, доступны все параметры выборки.Ниже представлены различные варианты загрузки.

  • ПЕРВЫЙ
  • ПОСЛЕДНИЙ
  • ПРИОР
  • СЛЕДУЮЩИЙ
  • РОДСТВЕННИК
  • АБСОЛЮТНЫЙ

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

Все изменения данных, сделанные после открытия курсора, не видны.Создайте курсор со свитком и сначала откройте его.

DECLARE DefaultCursor CURSOR SCROLL

FOR

SELECT id, name FROM Test

OPEN DefaultCursor

Теперь откройте еще один сеанс в студии управления SQL Server и обновите запись, где id = 1

Обновить набор тестов Имя = 'Lee' ГДЕ ID = 1

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

ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ DefaultCursor

Атрибуты SCROLL и FAST_FORWARD нельзя указывать вместе в курсоре.

СТАТИЧЕСКАЯ

Статический курсор при открытии создает копию данных, возвращаемых оператором select, указанным в операторе declare, и любые дальнейшие изменения данных не видны.Мы не можем обновлять или удалять данные с помощью CURRENT OF, поскольку они доступны только для чтения.

Создайте курсор с помощью STATIC и сначала откройте его.

DECLARE DefaultCursor CURSOR STATIC

FOR

SELECT id, name FROM Test

OPEN DefaultCursor

Теперь откройте еще один сеанс в студии управления SQL Server и обновите запись, где id = 1

Обновить тестовый набор Name = 'Peter' ГДЕ ID = 2

Теперь вернитесь к сеансу, в котором курсор был создан при выполнении приведенной ниже инструкции fetch два раза.Он по-прежнему показывает старое значение.

ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ DefaultCursor

ДИНАМИЧЕСКИЙ

Когда курсор создается с динамическим атрибутом, все изменения, внесенные в строки внутри курсора или вне курсора, видны, когда вы выбираете новую запись. По умолчанию, если STATIC или FAST_FORWARD не указаны, курсор создается как динамический.

Чтобы проиллюстрировать это, объявите и откройте курсор.

DECLARE DefaultCursor CURSOR DYNAMIC

FOR

SELECT id, name FROM Test

OPEN DefaultCursor

В другом сеансе вставьте еще несколько записей или обновите их.

INSERT INTO Test values ​​(3, 'Palmer')

Update Test set Name = 'Kevin', где id = 1

Теперь выполните оператор выборки в том же сеансе, где вы создали курсор.

FETCH NEXT FROM DefaultCursor

while @@ FETCH_STATUS = 0

begin

FETCH NEXT FROM DefaultCursor

end

Мы можем видеть, что изменения данных, сделанные за пределами курсора, отражаются при выборке строк.

FAST_FORWARD

Это включает READ_ONLY и FORWARD_ONLY на курсоре.Это самый быстрый курсор SQL Server, и любые изменения данных не видны после того, как курсор открыт. FAST_FORWARD нельзя указывать вместе с SCROLL или FOR_UPDATE.

Синтаксис для создания курсора с FAST_FORWARD

DECLARE DefaultCursor CURSOR FAST_FORWARD

FOR

SELECT id, name FROM Test

заказать по ID

ТОЛЬКО ДЛЯ ЧТЕНИЯ

Этот атрибут курсора не позволяет обновлять и удалять внутри курсора с помощью CURRENT OF.Любые изменения данных, произошедшие после открытия курсора, не видны.

SCROLL_LOCKS

Когда курсор создается с атрибутом SCROLL_LOCKS, строки, которые выбираются в курсор, блокируются.

Выполните приведенные ниже инструкции, чтобы создать курсор с SCROLL_LOCKS.

DECLARE DefaultCursor CURSOR SCROLL_LOCKS

FOR

SELECT id, name FROM Test

OPEN DefaultCursor

FETCH NEXT FROM DefaultCursor

Теперь откройте еще один сеанс в студии управления SQL Server и попробуйте обновить данные в таблице.Он будет заблокирован указанным выше курсором SQL Server.

ИМЯ ТЕСТОВОГО НАБОРА ОБНОВЛЕНИЯ = 'LockTest'

ОПТИМИСТИЧЕСКИЙ

Этот атрибут не будет обновлять или удалять данные внутри курсора с помощью CURRENT OF, когда данные изменяются другим пользователем в другом сеансе после выборки. Это вызывает ошибку, как показано на изображении ниже.

Он сравнивает временную метку или контрольную сумму, чтобы увидеть, была ли строка изменена после выборки.

ДЛЯ ОБНОВЛЕНИЯ

Этот атрибут определяет обновляемые столбцы в курсоре. Обновляются только указанные столбцы. Если список столбцов не был предоставлен, все столбцы таблицы могут быть обновлены.

Пример курсора без столбцов, указанных для обновления. В этом случае все столбцы в таблице test можно обновить внутри курсора SQL Server с помощью CURRENT OF.

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

DECLARE @id INT, @name VARCHAR (50)

DECLARE DefaultCursor CURSOR

FOR

SELECT id, name FROM Test

FOR UPDATE

INEX

OPEN

OPENCurs2 @id, @name

WHILE @@ FETCH_STATUS = 0

BEGIN

Тестовый набор UPDATE id = 1, name = 'Updatetest', где текущий DefaultCursor

FETCH NEXT FROM DefaultCursor INTO @id

КОНЕЦ

ЗАКРЫТЬ DefaultCursor

DEALLOCATE DefaultCursor

Пример курсора с указанием только одного столбца в списке обновлений.В этом случае мы не можем обновить столбец «id».

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

DECLARE @id INT, @name VARCHAR (50)

DECLARE DefaultCursor CURSOR

FOR

SELECT id, name FROM Test

FOR UPDATE of [name]

OPDATE of [name]

OPET СЛЕДУЮЩИЙ ОТ DefaultCursor INTO @id, @name

WHILE @@ FETCH_STATUS = 0

BEGIN

Тестовый набор UPDATE id = 1, name = 'Updatetest', где текущий DefaultCursor

FETCH NEXOR id, @name

END

ЗАКРЫТЬ DefaultCursor

DEALLOCATE DefaultCursor

Если мы попытаемся обновить столбец, которого нет в обновлении списка, это приведет к ошибке, как показано на изображении ниже.

Для просмотра свойств курсора используйте встроенную функцию sys.dm_exec_cursors. Это возвращает информацию об открытых курсорах для всех баз данных в экземпляре. Это возвращает информацию, например, в каком сеансе был открыт курсор, имя курсора и свойства. На изображении ниже показан набор результатов, возвращаемый встроенной функцией.

Надеюсь, вам понравилась эта статья о курсоре SQL Server.Не стесняйтесь оставлять отзывы в комментариях ниже.

Администратор баз данных SQL Server, разработчик с большим опытом администрирования, разработки, настройки производительности, мониторинга, обеспечения высокой доступности и аварийного восстановления SQL Server

Последние сообщения Ранги Бабу (посмотреть все)

Свойство курсора CSS


Пример

CSS может генерировать несколько разных курсоров мыши:

.alias {курсор: псевдоним;}
.all-scroll {курсор: all-scroll;}
.auto {cursor: auto;}
.cell {cursor: cell;}
.context-menu {cursor: context-menu;}
.col-resize {cursor: col-resize;}
.copy {cursor: copy;}
.crosshair {cursor: crosshair;}
.default {cursor: default;}
.e-resize {cursor: e-resize;}
.ew-resize {cursor: ew-resize;}
.grab {cursor: grab;}
.grabbing {cursor: grabbing;}
.help {cursor: help;}
.move {курсор: перемещение;}
.n-resize {cursor: n-resize;}
.ne-resize {курсор: ne-resize;}
.nesw-resize {cursor: nesw-resize;}
.ns-resize {курсор: ns-resize;}
.nw-resize {курсор: nw-resize;}
.nwse-resize {курсор: nwse-resize;}
.no-drop {cursor: no-drop;}
.none {cursor: none;}
.not-allowed {cursor: not-allowed;}
.pointer {cursor: pointer;}
.progress {cursor: прогресс;}
.row-resize {cursor: row-resize;}
.s-resize {курсор: s-resize;}
.se-resize {курсор: se-resize;}
.sw-resize {cursor: sw-resize;}
.text {cursor: text;}
.url {cursor: url (myBall.cur), auto;}
.w-resize {cursor: w-resize;}
.wait {cursor: wait;}
.zoom-in {cursor: zoom-in;}
.zoom-out {курсор: уменьшение масштаба;}

Попробуй сам "

Определение и использование

Свойство курсора определяет курсор мыши, который будет отображаться при наведении указателя на элемент.

Значение по умолчанию: авто
Унаследовано: да
Анимируемый: нет.Читать о анимации
Версия: CSS2
Синтаксис JavaScript: объект .style.cursor = "crosshair" Попытайся

Поддержка браузера

Числа в таблице указывают первую версию браузера, полностью поддерживающую свойство.

Недвижимость
курсор 5.0 5,5 4,0 5,0 9,6


Синтаксис CSS

Стоимость недвижимости

Значение Описание Играй
псевдоним Курсор указывает, что необходимо создать псевдоним Играй »
all-scroll Курсор указывает на то, что что-то можно прокручивать в любом направлении Играй »
авто По умолчанию.Браузер устанавливает курсор Играй »
ячейка Курсор указывает, что ячейка (или набор ячеек) может быть выбрана Играй »
контекстное меню Курсор указывает, что доступно контекстное меню Играй »
col изменить размер Курсор указывает, что размер столбца можно изменять по горизонтали Играй »
копия Курсор указывает, что что-то нужно скопировать Играй »
перекрестие Курсор отображается как перекрестие Играй »
по умолчанию Курсор по умолчанию Играй »
изменить размер Курсор указывает, что край прямоугольника необходимо переместить вправо (на восток) Играй »
изменение размера ew Обозначает двунаправленный курсор изменения размера. Играй »
грейфер Курсор указывает, что что-то можно схватить Играй »
захват Курсор указывает, что что-то можно схватить Играй »
справка Курсор указывает, что справка доступна Играй »
переместить Курсор указывает, что что-то нужно переместить Играй »
изменить размер Курсор указывает, что край прямоугольника необходимо переместить вверх (на север) Играй »
изменить размер Курсор указывает, что край прямоугольника нужно переместить вверх и вправо (север / восток) Играй »
изменить размер Обозначает двунаправленный курсор изменения размера. Играй »
нс изменить размер Обозначает двунаправленный курсор изменения размера. Играй »
изменить размер nw Курсор указывает, что край прямоугольника нужно переместить вверх и влево (север / запад) Играй »
изменить размер nwse Обозначает двунаправленный курсор изменения размера Играй »
без сброса Курсор указывает, что перетаскиваемый элемент не может быть удален сюда Играй »
нет Курсор не отображается для элемента Играй »
не допускается Курсор указывает, что запрошенное действие не будет выполнено Играй »
указатель Курсор является указателем и указывает ссылку Играй »
прогресс Курсор указывает, что программа занята (выполняется) Играй »
изменение размера строки Курсор указывает, что размер строки можно изменять по вертикали Играй »
s-изменить размер Курсор указывает на то, что край прямоугольника необходимо переместить вниз (на юг) Играй »
изменить размер Курсор указывает на то, что край прямоугольника нужно переместить вниз и вправо (юг / восток) Играй »
SW-изменение размера Курсор указывает, что край прямоугольника нужно переместить вниз и влево (юг / запад) Играй »
текст Курсор указывает текст, который можно выбрать Играй »
URL Список URL-адресов пользовательских курсоров, разделенных запятыми. Примечание: Всегда указывайте универсальный курсор в конце списка на случай, если ни один из курсоров, определенных для URL, не может быть использован Играй »
вертикальный текст Курсор указывает вертикальный текст, который можно выбрать Играй »
w изменить размер Курсор указывает, что край прямоугольника необходимо переместить влево (на запад) Играй »
подождите Курсор указывает, что программа занята Играй »
увеличение Курсор указывает на то, что что-то можно увеличить в Играй »
уменьшение Курсор указывает, что что-то можно уменьшить Играй »
начальный Устанавливает для этого свойства значение по умолчанию.Читать о начальных Играй »
унаследовать Наследует это свойство от своего родительского элемента. Читать про наследство

Связанные страницы

Ссылка на HTML DOM: свойство курсора



вложенных курсоров в T-SQL - блог Truelogic

У нас есть две примерные таблицы:

  • треков - в которых хранится информация об аудиодорожках
  • соответствует - таблица, в которой хранятся сопоставленные треки во внешних данных

Как вы можете видеть в строках таблицы ниже, поле Id таблицы дорожек является внешним ключом в таблице совпадений в форме trackId.В примере кода T-SQL показано, как перебирать строки в совпадениях, а затем извлекать строку дорожки для этой дорожки из таблицы дорожек. Очевидно, имеет смысл просто выполнить JOIN, но этот код больше предназначен для демонстрации циклов вложенного курсора, чем для чего-либо особенно полезного.

Таблица треков приведена ниже:

Таблица совпадений приведена ниже:

Код T-SQL приведен ниже в форме хранимой процедуры.

 USE [Данные]
ИДТИ

УСТАНОВИТЬ ANSI_NULLS ON
ИДТИ
ВКЛЮЧИТЬ QUOTED_IDENTIFIER
ИДТИ
изменить ПРОЦЕДУРУ [dbo]. [Test_Nested_Cursors]

В ВИДЕ
НАЧАТЬ
 объявить @trackid как int

 объявить курсор @outer_cursor
 объявить курсор @inner_cursor

 объявить @matchid как int
 объявить @stationid как int
 объявить @thistrackid как int
 объявить @matchdate как datetime
 объявить @matchtimestart как datetime
 объявить @matchtimeend как datetime
 объявить @streamfile как varchar (100)

 объявить @fetch_outer_cursor int
 объявить @fetch_inner_cursor int

 объявить курсор external_cursor статическим локальным для
 ВЫБРАТЬ
  ТОП 1000
      [TrackId]
  ИЗ [Данные].[dbo]. [совпадения]
  
  / * цикл по курсору верхнего уровня * /
  открыть external_cursor
  получить следующий из outer_cursor в @trackid
  выберите @fetch_outer_cursor = @@ FETCH_STATUS

  а @fetch_outer_cursor = 0
  начать
print cast (@trackid как varchar (20))

/ * перебираем курсор второго уровня * /
установить @inner_cursor = курсор статический локальный для
выберите первые 100 идентификаторов, Stationid, trackid, date, matchtimestart, matchtimeend, streamfile
из совпадений, где trackid = @trackid, порядок MatchTimeStart


открыть @inner_cursor
получить далее из @inner_cursor в @matchid, @stationid, @thistrackid, @matchdate, @matchtimestart, @matchtimeend, @streamfile
установить @fetch_inner_cursor = @@ FETCH_STATUS
а @fetch_inner_cursor = 0
начать

print cast (@matchid as varchar (20)) + ',' + cast (@stationid as varchar (20)) + ',' + cast (@thistrackid как varchar (20)) +
',' + cast (@matchtimestart как varchar (30)) + '-' + cast (@matchtimeend как varchar (30))

получить далее из @inner_cursor в @matchid, @stationid, @thistrackid, @matchdate, @matchtimestart, @matchtimeend, @streamfile
установить @fetch_inner_cursor = @@ FETCH_STATUS
конец
закрыть @inner_cursor
освободить @inner_cursor

 получить следующий из external_cursor в @trackid
установить @fetch_outer_cursor = @@ FETCH_STATUS


  конец
 
  закрыть match_cursor
  освободить match_cursor
конец
 

Некоторые моменты, которые следует отметить в сценарии:

  • После получения каждой таблицы в курсоре мы сохранили @@ FETCH_STATUS в переменной (@ fetch_outer_cursor, @ fetch_inner_cursor).Это помогает сохранить состояние курсоров, поскольку мы используем несколько курсоров вместе. Если мы проверили напрямую @@ FETCH_STATUS = 0, то он вернет статус последней операции курсора, какой бы она ни была. В этом коде после первой итерации внутреннего курсора внешний курсор вызовет исключение, поскольку внутренний курсор перезаписал бы состояние внешнего курсора.
  • Внутренний курсор закрывается и освобождается перед повторным повторением внешнего цикла, чтобы предотвратить утечку памяти
  • При необходимости это вложение может быть расширено до 3 или 4 уровней, пока состояние курсора сохраняется для каждого уровня.

Курсор в SQL Server

Курсор - это объекты базы данных, используемые для получения данных из набора результатов по одной строке за раз, вместо команд T-SQL, которые работают со всеми строками в наборе результатов одновременно. Курсор используется, когда пользователю необходимо обновлять записи в таблице базы данных построчно.

Жизненный цикл курсора

1. Объявление курсора
Курсор объявляется путем определения оператора SQL, который возвращает набор результатов.

Синтаксис:
Записка SQL для объявления курсора и используется для определения курсора со многими параметрами, которые влияют на масштабируемость и поведение курсора при загрузке. Базовый синтаксис приведен ниже:

DECLARE имя_курсора CURSOR
[LOCAL & verbar; GLOBAL] - определить область действия курсора
[FORWARD_ONLY & verbar; SCROLL] - определение движения курсора (вперед / назад)
[STATIC & verbar; KEYSET и глагол; ДИНАМИЧЕСКИЙ & глагол; FAST_FORWARD] - базовый тип курсора
[READ_ONLY & verbar; SCROLL_LOCKS & verbar; OPTIMISTIC] - определить блокировки FOR select_statement --define SQL Оператор выбора
FOR UPDATE [col1, col2 ,...coln] - определить столбцы, которые необходимо обновить.


2. Открыть
Курсор открывается путем выполнения оператора SQL, определенного курсором.

Синтаксис:
Курсор можно открыть локально или глобально. По умолчанию он открывается локально. Базовый синтаксис для открытия курсора приведен ниже:

OPEN [GLOBAL] имя_курсора - по умолчанию это локальный

3. Выборка
Когда курсор открыт, строки могут выбираться из курсора одну за другой или в блоке для обработки данных.

Синтаксис:
Оператор Fetch предоставляет множество вариантов для извлечения строк из курсора. ДАЛЕЕ - опция по умолчанию. Базовый синтаксис для выборки курсора приведен ниже:

FETCH [NEXT & verbar; PRIOR & verbar; FIRST & verbar; LAST & verbar; ABSOLUTE n & verbar; RELATIVE n] FROM [GLOBAL] имя_курсора INTO & commat; Variable_name] [1,2, .. n] 4. Закройте После обработки данных мы должны явно закрыть курсор.

Синтаксис:
Оператор Close явно закрывает курсор. Базовый синтаксис для закрытия курсора приведен ниже:

CLOSE имя_курсора - после закрытия его можно снова открыть

5. Освободить
Наконец, нам нужно удалить определение курсора и освободить все системные ресурсы, связанные с курсор.

Синтаксис:
DEALLOCATE имя_курсора - после освобождения его нельзя открыть повторно

Простой пример курсора

Рассмотрим следующую таблицу под названием «Сотрудник».
EmpID Имя Заработная плата Адрес
1 Джей 12000 Мумбаи
2 Райан 25000 Дели
Анна 22000 Baroda
4 Альберт 22000 Мумбаи
5 Satya 28000 Pune

Напишите запрос T-SQL для отображения записей сотрудников с помощью курсора.

SET NOCOUNT ON
DECLARE & commat; Id int
DECLARE & commat; name varchar (50)
DECLARE & commat; salary int
DECLARE cur_emp CURSOR
STATIC FOR SELECT EmpID, EmpName 908, Salary from CURSOR_ROWS> 0
BEGIN
FETCH NEXT FROM cur_emp INTO & commat; Id, & commat; name, & commat; salary
WHILE & commat; & commat; Fetch_status = 0
BEGIN
PRINT 'ID:' + convert (varchar (20), & commat; Id) + ', Name:' + & commat; name + ', Salary:' + convert (varchar (20), & commat; salary) + '
FETCH NEXT FROM cur_emp INTO & commat; Id, & commat; name, & commat; salary
END
END
CLOSE cur_emp
DEALLOCATE cur_emp
SET NOCOUNT OFF


Выход:
ID: 1, Имя: Джей, Заработная плата: 12000
ID: 1, Имя: Райан, Заработная плата: 25000
ID: 1, Имя: Анна, Заработная плата: 22000
ID: 1, Имя: Альберт, Заработная плата: 22000
ID: 1, Имя: Сатья, Заработная плата: 28000.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *