Содержание

Использование курсоров и циклов в Transact-SQL | Info-Comp.ru

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

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

Существует процедура, которая выполняет какие-то действия, которые не может выполнить обычная функция SQL например, расчеты и insert на основе этих расчетов. И Вы ее запускаете, например вот так:

EXEC test_PROCEDURE par1, par2

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

SELECT my_fun(id) FROM test_table

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

Примечание! Все примеры будем писать в СУБД MS SQL Server 2008, используя Management Studio. Также все нижеперечисленные действия требуют определённых знаний языка SQL, а точнее Transact-SQL. Начинающим могу посоветовать посмотреть мой видеокурс по T-SQL, на котором рассматриваются все базовые конструкции.

И так приступим, и перед тем как писать процедуру, давайте рассмотрим исходные данные нашего примера.

Допустим, есть таблица test_table

   
   CREATE TABLE [dbo].[test_table](
        [number] [numeric](18, 0) NULL,
        [pole1] [varchar](50) NULL,
        [pole2] [varchar](50) NULL
   ) ON [PRIMARY]

GO

В нее необходимо вставлять данные, на основе каких-то расчетов, которые будет выполнять процедура

my_proc_test, в данном случае она просто вставляет данные, но на практике Вы можете использовать свою процедуру, которая может выполнять много расчетов, поэтому в нашем случае именно эта процедура не важна, она всего лишь для примера. Ну, давайте создадим ее:

   
   CREATE PROCEDURE [dbo].[my_proc_test]
     (@number numeric, @pole1 varchar(50),  @pole2 varchar(50))
   AS
   BEGIN
    INSERT INTO dbo.test_table (number, pole1, pole2) 
       VALUES (@number, @pole1, @pole2)
   END
   GO


Она просто принимает три параметра и вставляет их в таблицу.

И допустим эту процедуру, нам нужно запустить столько раз, сколько строк в какой-нибудь таблице или представлении (VIEWS) ,  другими словами запустить ее массово для каждой строки источника.

И для примера создадим такой источник, у нас это будет простая таблица test_table_vrem, а у Вас это может быть, как я уже сказал свой источник, например временная таблица или представление:

   
   CREATE TABLE [dbo].[test_table_vrem](
        [number] [numeric](18, 0) NULL,
        [pole1] [varchar](50) NULL,
        [pole2] [varchar](50) NULL
   ) ON [PRIMARY]

  GO


Заполним ее тестовыми данными:

Скриншот 1

Авторские онлайн-курсы по T-SQL

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

exec my_proc_test 1, ‘pole1_str1’, ‘pole2_str1’

И так еще три раза, с соответствующими параметрами.

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

Первый вариант.

Используем курсор и цикл в процедуре

Перейдем сразу к делу и напишем процедуру (my_proc_test_all), код я как всегда прокомментировал:

   
   CREATE PROCEDURE [dbo].[my_proc_test_all]
   AS
  
   --объявляем переменные
   DECLARE @number bigint
   DECLARE @pole1 varchar(50)
   DECLARE @pole2 varchar(50)
   
   --объявляем курсор
   DECLARE my_cur CURSOR FOR 
     SELECT number, pole1, pole2 
     FROM test_table_vrem
   
   --открываем курсор
   OPEN my_cur
   --считываем данные первой строки в наши переменные
   FETCH NEXT FROM my_cur INTO @number, @pole1, @pole2
   --если данные в курсоре есть, то заходим в цикл
   --и крутимся там до тех пор, пока не закончатся строки в курсоре
   WHILE @@FETCH_STATUS = 0
   BEGIN
        --на каждую итерацию цикла запускаем нашу основную процедуру с нужными параметрами   
        exec dbo.my_proc_test @number, @pole1, @pole2
        --считываем следующую строку курсора
        FETCH NEXT FROM my_cur INTO @number, @pole1, @pole2
   END
   
   --закрываем курсор
   CLOSE my_cur
   DEALLOCATE my_cur
   GO


И теперь осталось нам ее вызвать и проверить результат:

Скриншот 2

Код:

   
   --до выполнения процедуры
   SELECT * FROM test_table

   --вызов процедуры
   EXEC dbo.my_proc_test_all

   --после выполнения процедуры
   SELECT * FROM test_table 


Как видите, все у нас отработало как надо, другими словами процедура my_proc_test сработала все три раза, а мы всего лишь один раз запустили дополнительную процедуру.

Второй вариант.

Используем только цикл в процедуре

Сразу скажу, что здесь требуется нумерация строк во временной таблице, т.е. каждая строка должна быть пронумерована, например 1, 2, 3 таким полем у нас во временной таблице служит number.

Пишем процедуру my_proc_test_all_v2

   
   CREATE PROCEDURE [dbo].[my_proc_test_all_v2]
   AS
   --объявляем переменные
   DECLARE @number bigint
   DECLARE @pole1 varchar(50)
   DECLARE @pole2 varchar(50)
   DECLARE @cnt int
   DECLARE @i int 
   
   --узнаем количество строк во временной таблице
   SELECT @cnt=count(*) 
   FROM test_table_vrem

   --задаем начальное значение идентификатора
   SET @i=1
   WHILE @cnt >= @i
   BEGIN
        --присваиваем значения нашим параметрам
        SELECT @number=number, @pole1= pole1, @pole2=pole2 
        FROM test_table_vrem 
        WHERE number = @I

        --на каждую итерацию цикла запускаем нашу основную процедуру с нужными параметрами   
        EXEC dbo.my_proc_test @number, @pole1, @pole2

        --увеличиваем шаг
        set @i= @i+1
        
   END
   GO


И проверяем результат, но для начала очистим нашу таблицу, так как мы же ее только что уже заполнили по средствам процедуры my_proc_test_all:

Скриншот 3

   
   --очистим таблицу
   DELETE test_table
   
   --до выполнения процедуры
   SELECT * FROM test_table
   
   --вызов процедуры
   EXEC dbo.my_proc_test_all_v2
   
   --после выполнения процедуры
   SELECT * FROM test_table


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

Заметка! Если Вас интересует SQL и T-SQL, рекомендую посмотреть мои видеокурсы по T-SQL, с помощью которых Вы «с нуля» научитесь работать с SQL и программировать с использованием языка T-SQL в Microsoft SQL Server.

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

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

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

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

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

Курсор в 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. В курсоре видно самое последнее состояние данных.

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

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 @salescursor=@sc — Возвращаем курсор с помощью выходного параметра

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


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

Заключение


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

НОУ ИНТУИТ | Лекция | Курсоры в Transact-SQL

Аннотация: Курсор – это особый временный объект SQL, предназначенный для использования в программах и хранимых процедурах. С его помощью можно в цикле пройти по результирующему набору строк запроса, по отдельности считывая и обрабатывая каждую его строку. В хранимых процедурах с помощью курсоров можно выполнять сложные вычисления, которые трудно выразить с помощью синтаксиса инструкции SELECT. Большой теоретический материал урока дополнен очень хорошими примерами. В частности, рассматривается применение функции CURSOR_STATUS, описание переменных @@CURSOR_ROWS и @@FETCH_STATUS, и многое другое.

Вы научитесь:

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

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

Например, поскольку нет возможности указать на определенную строку во множестве, представление пользователю строк по одной за раз может вызвать затруднения. Даже несмотря на то, что предоставляемые Transact-SQL расширения к стандартному языку SQL позволяют реализовать гораздо большие возможности для программирования, тем не менее остаются операции, которые затруднительно, трудоемко или даже вообще невозможно выполнить на основе принципов работы с множествами.

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

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

Microsoft SQL Server реально поддерживает два различных типа курсоров: курсоры Transact-SQL и курсоры API (курсоры программного интерфейса приложений). Курсоры API создаются внутри приложения, использующего объекты Microsoft ActiveX Data Objects (ADO), OLE DB, ODBC или DB-Library. Каждое из этих API поддерживает несколько отличающиеся функциональные возможности и использует различный синтаксис. Здесь мы не будем подробно обсуждать курсоры API; если вы планируете использовать их, обратитесь к соответствующей документации на API и языку программирования, который вы собираетесь применить.

Курсоры Transact-SQL создаются с помощью команды DECLARE CURSOR. Как объект курсора, так и множество строк, на которое он указывает, должны существовать на сервере. Подобные курсоры называются серверными курсорами. Если вы используете серверный курсор из приложения, соединенного с SQL Server через сеть, каждая операция с курсором требует двустороннего сетевого взаимодействия. Библиотеки API-курсоров, поддерживающие серверные курсоры, поддерживают также клиентский курсор, который существует в клиентской системе и кэширует строки, которые он обрабатывает на клиенте.

Множество строк, на которое указывает курсор, определяется с помощью команды SELECT. При создании курсора Transact-SQL на команду SELECT накладываются несколько ограничений:

  • команда SELECT не может возвращать несколько результирующих множеств;
  • команда SELECT не может содержать фразу INTO для создания новой таблицы;
  • команда SELECT не может содержать фразу COMPUTE или COMPUTE BY, используемые для агрегирования результатов. (Однако, она может содержать функции агрегирования, например, AVG.)
Характеристики курсоров

Transact-SQL поддерживает несколько различных типов курсоров. Выяснение различных характеристик каждого из курсоров является довольно утомительной задачей, но ее можно облегчить, если принять во внимание для каждого типа курсора три более или менее независимых характеристики: способность отражать изменения в исходных данных, способность осуществлять прокрутку во множестве строк, а также способность модифицировать множество строк.

Отражение изменений

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

SELECT * FROM Oils
WHERE Left(OilName, 1) = 'B'

База данных Aromatherapy вернет четыре строки, как показано на рис. 27.1. Если в процессе использования вами курсора кто-либо добавит значение Description для элемента Bergamot, либо добавит строку для элемента Bayberry, что произойдет с множеством строк, на которое указывает ваш курсор?

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

Прокрутка

Второй характеристикой курсора является способность осуществления прокрутки как вперед, так и назад, либо только вперед. Здесь имеет место извечная для программирования дилемма: скорость против гибкости. Последовательные курсоры (forward-only) работают значительно быстрее, но имеют меньшую гибкость.

Обновление

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

Курсоры (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 при работе с курсорами

Здравствуй, человек-читатель блогов на Community.

Хочу рассказать о своем недавнем опыте оптимизации курсора в SQL Server.
Первое, что нужно знать, курсор – это не хорошо, а плохо. Где есть возможность заменить курсор на INSERT SELECT или на использование временной таблицы, там нужно это сделать (за редким исключением). Курсор – это почти всегда дополнительные ресурсы сервера и резкое падение производительности по сравнению с другими решениями.
Второе, иногда без курсора не обойтись – там где не обойтись без построчного прохода по результату выборки. Вот в таких случаях очень важно правильно создать нужный тип курсора – тот, который соответствует решаемой задаче. Общий синтаксис объявления курсора имеет вид:

DECLARE cursor_name CURSOR
[ LOCAL | GLOBAL ]
[ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
[ TYPE_WARNING ]
FOR select_statement
[ FOR UPDATE [ OF column_name [ ,…n ] ] ] [;]

Остановлюсь на первых трех строчках ключевых параметров.
    LOCAL или GLOBAL:    если хотим, чтобы курсор был доступен другим процедурам, функциям, пакетам в рамках нашей сессии, то GLOBAL – в этом случае за удалением курсора следим сами (команда DEALLOCATE). Во всех остальных случаях (т.е. в подавляющем своем большинстве) – LOCAL. Внимание, по умолчанию создается именно GLOBAL курсор!
    FORWARD_ONLY или SCROLL: если хотим ходить по курсору, как ненормальные, туда-сюда, то SCROLL, иначе – FORWARD_ONLY. Внимание, по умолчанию создается SCROLL курсор!
    STATIC или KEYSET, DYNAMIC, FAST_FORWARD: если хотим, чтобы при проходе по курсору отображалась актуальная информация из таблицы (т.е., если после открытия курсора, мы поменяли информацию в одном из полей таблицы и хотим, чтобы при проходе по курсору в нужной строчке курсора была уже обновленная информация), то используем или KEYSET (если КАЖДАЯ таблица, участвующая в выборке, имеет уникальный индекс) или DYNAMIC (самый медленный тип). Если же нам нужен снимок результата выборки после открытия курсора – STATIC (самый быстрый тип – копия результата выборки копируется в базу tempdb и работаем уже с ней). FAST_FORWARD = KEYSET+FORWARD_ONLY+READ_ONLY – пацаны из инета пишут, что STATIC дольше открывается (т.к. создается копия в tempdb), но быстрее работает, а FAST_FORWARD – наоборот. Так что если количество записей велико (насколько большое показывает практика), то применяем STATIC, иначе – FAST_FORWARD. Внимание, по умолчанию создается DYNAMIC курсор.

Таким образом, для большого кол-ва записей в большинстве случаев мой выбор:
DECLARE cursor_name CURSOR LOCAL FORWARD_ONLY STATIC FOR
select_statemen
t

для небольшого кол-ва записей:
DECLARE cursor_name CURSOR LOCAL FAST_FORWARD FOR
select_statement

Теперь перейдем к практике (что собственно и подтолкнуло меня к писанине сего).
Испокон веков при объявлении курсора я применял конструкцию DECLARE … CURSOR LOCAL FOR…
При разработке интеграции с одной очень нехорошей базой, в которой нет ни одного индекса и не одного ключа, я применил тот же подход при объявлении курсоров, что и всегда. Выборка одного курсора содержала 225 000 записей. В результате процесс импорта данных из такой базы занял 15 часов 14 минут !!! И хотя импорт и был первичный (т.е. одноразовый), но даже для нормального тестирования такого импорта потребовалось бы несколько суток! После замены вышеназванной конструкции при объявлении курсора на DECLARE .. CURSOR LOCAL FORWARD_ONLY STATIC FOR.. весь процесс импорта занял … внимание … 10 минут 5 секунд !!! Так что игра точно стоит свеч.
Хочу повториться, что идеальный вариант — это все же не использовать курсоры вообще — для СУБД MS SQL намного роднее реляционный, а не навигационный подход.

ОБЪЯВЛЕНИЕ КУРСОРА — Oracle PL/SQL •MySQL •MariaDB •SQL Server •SQLite

В этом учебном материале вы узнаете, как объявить курсор в Oracle/PLSQL c синтаксисом и примерами.

Описание

Курсор это определенный оператор SELECT, который объявлен в PLSQL коде. Рассмотрим три различных синтаксиса объявления курсора.

КУРСОР БЕЗ ПАРАМЕТРОВ (ПРОСТОЙ)

Объявление курсора без каких-либо параметров, простой курсор.

Синтаксис

CURSOR cursor_name
IS
SELECT_statement;

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

CURSOR c1 IS SELECT course_number FROM courses_tbl WHERE course_name = name_in;

CURSOR c1

IS

  SELECT course_number

  FROM courses_tbl

  WHERE course_name = name_in;

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

CREATE OR REPLACE Function FindCourse ( name_in IN varchar2 ) RETURN number IS cnumber number; CURSOR c1 IS SELECT course_number FROM courses_tbl WHERE course_name = name_in; BEGIN OPEN c1; FETCH c1 INTO cnumber; if c1%notfound then cnumber := 9999; end if; CLOSE c1; RETURN cnumber; END;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

CREATE OR REPLACE Function FindCourse

   ( name_in IN varchar2 )

   RETURN number

IS

   cnumber number;

   CURSOR c1

   IS

     SELECT course_number

     FROM courses_tbl

     WHERE course_name = name_in;

BEGIN

   OPEN c1;

   FETCH c1 INTO cnumber;

   if c1%notfound then

      cnumber := 9999;

   end if;

   CLOSE c1;

RETURN cnumber;

END;

КУРСОР С ПАРАМЕТРАМИ

Объявим курсор с параметрами.

Синтаксис

CURSOR cursor_name (parameter_list)
IS
SELECT_statement;

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

CURSOR c2 (subject_id_in IN varchar2) IS SELECT course_number FROM courses_tbl WHERE subject_id = subject_id_in;

CURSOR c2 (subject_id_in IN varchar2)

IS

  SELECT course_number

  FROM courses_tbl

  WHERE subject_id = subject_id_in;

Результирующий набор этого курсора все course_numbers, у которых subject_id соответствует subject_id полученные курсором с помощью параметра subject_id_in.

КУРСОР С ВОЗВРАЩАЮЩИМ УСЛОВИЕМ

Наконец, мы можем объявить курсор с возвращающим условием.

Синтаксис

CURSOR cursor_name
RETURN field%ROWTYPE
IS
SELECT_statement;

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

CURSOR c3 RETURN courses_tbl%ROWTYPE IS SELECT * FROM courses_tbl WHERE subject = ‘Mathematics’;

CURSOR c3

RETURN courses_tbl%ROWTYPE

IS

   SELECT *

   FROM courses_tbl

   WHERE subject = ‘Mathematics’;

Результирующим набором этого курсора будут все столбцы course_tbl, у которых subject будет ‘Mathematics’.

Курсоры в SQL

Курсор в SQL

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

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

Существуют следующие два типа курсоров в SQL:

  1. неявный курсор
  2. явный курсор

неявный курсор

Эти типы курсоров создаются и используются системой во время манипулирования DML-запросом (INSERT, UPDATE и DELETE). Неявный курсор также генерируется системой, когда команда SELECT выбирает одну строку.

Явный курсор

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

Основные компоненты курсоров

Каждый курсор содержит следующие 5 частей:

  1. Объявление курсора: в этой части мы объявляем переменные и возвращаем набор значений.
  2. Открыть: это входная часть курсора.
  3. Fetch: используется для извлечения данных строка за строкой из курсора.
  4. Закрыть: это выходная часть курсора, используемая для закрытия курсора.
  5. Deallocate: в этой части мы удаляем определение курсора и освобождаем все системные ресурсы, связанные с курсором.

Синтаксис курсора

  1. DECLARE @Variable nvarchar (50) / * Объявить все необходимые переменные * /
  2. DECLARE Cursor_Name CURSOR / * Объявить имя курсора * /
  3. [LOCAL | GLOBAL] / * Определить область действия курсора * /
  4. [FORWARD_ONLY | SCROLL] / * Определить направление движения курсора * /
  5. [KEYSET | DYNAMIC | STATIC | FAST_FORWARD] / * Определить базовый тип курсора * /
  6. [SCROLL_LOCKS | OPTIMISTIC | READ_ONLY] / * Определить блокировки * /
  7. OPEN Cursor_Name / * Открыть курсор * /
  8. FETCH NEXT FROM Cursor_Name / * Извлечь данные из Cursor * /
  9. Внедрить SQL QUery
  10. CLOSE Cursor_Name / * Clsoe * /
  11. DEALLOCATE Cursor_Name / * Отмена выделения всех ресурсов и памяти * /

Теперь мы объясним 4 важных терминологии курсоров.

Область курсора

Microsoft SQL Server поддерживает ключевые слова GLOBAL и LOCAL в операторе DECLARE CURSOR для определения области действия имени курсора.

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

Опция выборки данных в курсорах

Microsoft SQL Server поддерживает следующие две опции выборки данных:

  1. FORWARD_ONLY — указывает, что курсор можно прокручивать только от первой до последней строки.
  2. SCROLL — предоставляет 6 вариантов извлечения данных (ПЕРВЫЙ, ПОСЛЕДНИЙ, ПРИОРИТЕТНЫЙ, СЛЕДУЮЩИЙ, ОТНОСИТЕЛЬНЫЙ и АБСОЛЮТНЫЙ).

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

Microsoft SQL Server поддерживает следующие 4 типа курсоров.

  1. STATIC CURSOR
    Статический курсор заполняет результирующий набор при создании курсора, а результат запроса кэшируется на весь срок службы курсора. Статический курсор может двигаться вперед и назад.
  2. FAST_FORWARD
    Это тип курсора по умолчанию.Он идентичен статическому, за исключением того, что вы можете прокручивать только вперед.
  3. ДИНАМИЧНЫЙ
    В динамическом курсоре добавления и удаления видны для других в источнике данных, когда курсор открыт.
  4. KEYSET
    Это похоже на динамический курсор, за исключением того, что мы не можем видеть записи, добавленные другими. Если другой пользователь удаляет запись, она недоступна из нашего набора записей.

Типы блокировок

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

Microsoft SQL Server поддерживает следующие три типа блокировок.

  1. READ ONLY
    Указывает, что курсор не может быть обновлен.
  2. SCROLL_LOCKS
    Обеспечивает целостность данных в курсоре.Он указывает, что курсор будет блокировать строки при их считывании в курсор, чтобы обеспечить успешное обновление или удаление, выполненные с использованием курсора.
  3. OPTIMISTIC
    Указывает, что курсор не блокирует строки, когда они считываются в курсор. Таким образом, обновления или удаления, сделанные с помощью курсора, не будут выполнены, если строка была обновлена ​​вне курсора.

Сначала создадим таблицу, как показано ниже:

  1. GO
  2. CREATE TABLE [dbo].[Employee] (
  3. [Emp_ID] [int] NOT NULL,
  4. [Emp_Name] [nvarchar] (50) NOT NULL,
  5. [Emp_Salary] [int] NOT NULL,
  6. [Emp_City] [nvarchar] (50 ) NOT NULL,
  7. CONSTRAINT [PK_Employee] ПЕРВИЧНЫЙ КЛЮЧ КЛАСТЕРНЫЙ
  8. (
  9. [Emp_ID] ASC
  10. ) С (PAD_INDEX = ВЫКЛ., STATISTICS_NORECOMPUTE = ВЫКЛ., IGNORE_DUP_KEY = ВЫКЛ., ALLOW_ROW = ONLOW_WOR) ]
  11. ) ПО [ПЕРВИЧНОМУ]
  12. GO
Теперь вставьте в таблицу некоторые значения, как показано ниже:
  1. Вставьте в сотрудника
  2. Выберите 1, «Панкадж», 25000, «Алвар» Союз Все
  3. Выберите 2, «Рахул», 26000, «Алвар» Союз Все
  4. Выбрать 3, «Сандип», 25000, «Алвар» Союз Все
  5. Выбрать 4, «Санджив», 24000, «Алвар» Союз Все
  6. Выбрать 5, «Неерадж», 28000, «Альвар» Союз Все
  7. Выберите 6, ‘Нару’, 20000, ‘Альвар’ Союз Все
  8. Выберите 7, ‘Оми’, 23000, ‘Алвар’

Выберите все значения из таблицы, как показано ниже,

Пример 1

  1. SET NOCOUNT ON
  2. ОБЪЯВИТЬ @EMP_ID INT
  3. ЗАКЛЮЧИТЬ @EMP_NAME NVARCHAR (МАКС.)
  4. ОТКЛЮЧИТЬ @EMP_SALARY INT
  5. ОТКРЫТЬ @EMP_CITY
    1818000000000000 ВСТАВИТЬ СВОБОДНЫЙ КАРТОЧКОВЫЙ УСТРОЙСТВО

    0_1700 КВАРТАЛЬНЫЙ СБОРНИК ДЛЯ НОВОГО ЗВУКА КАРТИНКА СЕМЬЯ ДЖОРДЖАРА

    18172 УНИВЕР САРКА КВАРТАРА 1800-ЕГО ПОСМОТРЕТЬ НАВАРНУЮ КАРТУ (9002) 1817 УНИВЕРСАЛЬНЫЙ СРЕДНИЙ КАРТОЧЕВНИК (
    ) 1817 УНИВЕРСАЛЬНЫЙ МАГАЗИН ДЖАРДЖАРА
    18172 УНИВЕР САРКА (1800) ДЛЯ
  6. ВЫБРАТЬ * ИЗ Empl oyee
  7. ОТКРЫТЬ EMP_CURSOR
  8. ВЫБРАТЬ СЛЕДУЮЩУЮ ОТ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  9. WHILE @@ FETCH_STATUS = 0
  10. НАЧАЛО ПЕРЕДАЧИ ЭФФЕКТА (+)
  11. ПЕРЕДВИЖНЫМ (ПЕРЕДНЕГО ВИДА (EMAR) ПЕРЕДАЧИ: EMP_ID) + ‘EMP_NAME’ + @ EMP_NAME + ‘EMP_SALARY’ + CONVERT (NVARCHAR (MAX), @ EMP_SALARY) + ‘EMP_CITY’ + @ EMP_CITY
  12. FETCH СЛЕДУЮЩАЯ ИЗ EMP_CURSOR INTO @EMP_ID, @ EMP_ID, EMP_AME, EMP_AME, EMP_AME, EMP_AME, EMP_AME, EMP_AME, EMP_ID, EMP_ID, EMP_ID, EMP_ID, EMP_AME, EMP_AME, EMP_AME, EMP_AME @ EMP_ID, @ EMP_AME, EMP_AME @ EMP_ID, @ EMP_AME: EMP_ID @ EMP_ID, @ EMP_ID, @ EMP_ID, @ EMP_ID, @ EMP_ID, @ EMP_ID, @ EMP_ID, @ EMP_ID, @ EMP_ID, @ EMP_ID.
  13. КОНЕЦ
  14. ЗАКРЫТЬ EMP_CURSOR
  15. DEALLOCATE EMP_CURSOR
Выходной

    EMP_ID: 1 EMP_NAME Панкай EMP_SALARY 25000 EMP_CITY Алвар
    EMP_ID: 2 EMP_NAME Рахул EMP_SALARY 26000 EMP_CITY Алвар
    EMP_ID: 3 EMP_NAME Сандип EMP_SALARY 25000 EMP_CITY Алвар
    EMP_ID: 4 EMP_NAME Санджив EMP_SALARY 24000 EMP_CITY Alwar
    EMP_ID: 5 EMP_NAME Neeraj EMP_SALARY 28000 EMP_CITY Alwar
    EMP_ID: 6 EMP_NAME Нару EMP_SALARY 20000 EMP_CITY Alwar
    EMP_ID: 7 EMP_NAME Omi EMP_SALARY 23000 EMP_CITY Alwar

Это простой пример курсора, который печатает значение таблицы.

Пример 2 (SCROLL)

  1. SET NOCOUNT ON
  2. DECLARE @EMP_ID INT
  3. DECLARE @EMP_NAME NVARCHAR (MAX)
  4. DECLARE @EMAR_DEMAR DEMAR 9009
  5. 1818EAR DEMAR XEMAR DEMAR (900)
  6. ОБЪЯВИТЬ EMP_CURSOR CURSOR
  7. ЛОКАЛЬНЫЙ СВИТОК ДЛЯ
  8. ВЫБРАТЬ * ИЗ СОТРУДНИКА
  9. ОТКРЫТЬ EMP_CURSOR
  10. ВЫБРАТЬ В СЛЕДУЮЩЕМ ИЗ EMP_CURSOR В @EMP_ID, @ EMP_NAME_2003 , @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  11. ПЕЧАТЬ ‘EMP_ID:’ + + CONVERT (NVARCHAR (MAX), @ EMP_ID) + ‘EMP_NAME’ + @ EMP_NAME + ‘EMP_SALARY’ + CONVERT (NVARCHAR (MAX) + @ EMP_ @) ‘EMP_CITY’ + @ EMP_CITY
  12. FETCH ABSOLUTE 3 FROM EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  13. ПЕЧАТЬ ‘EMP_ID:’ + CONVERT (NVARCHAR (MAX) @ P_ID) + ‘EMP_NAME’ + @ EMP_NAME + ‘EMP_SALARY’ + CONVERT (NVARCHAR (MAX), @ EMP_SALARY) + ‘EMP_CITY’ + @ EMP_CITY
  14. ПЕРВЫЙ ВЫБОР ИЗ EMP_CURSOR INTO @ 900P_ID, EMP_ EMP_ID, EMP_ID, EMP_ID, EMP_AME, EMP_AME
  15. ПЕЧАТЬ ‘EMP_ID:’ + CONVERT (NVARCHAR (MAX), @ EMP_ID) + ‘EMP_NAME’ + @ EMP_NAME + ‘EMP_SALARY’ + CONVERT (NVARCHAR (MAX), @ EMP_SALARY) + ‘EMP_CITY’ + @ EMP_CET
  16. ОТ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  17. ПЕЧАТЬ ‘EMP_ID:’ + + CONVERT (NVARCHAR (MAX), @ EMP_ID) + ‘EMP_NAME’ + @ EMP_NAME + (EMAR_SALARY) + ‘EMP_SALARY’ ‘EMP_SALARY’ + EMCH_SALARY + ‘EMP_SALARY’ + EMP_SALARY , @ EMP_SALARY) + ‘EMP_CITY’ + @ EMP_CITY
  18. ВЫБРАТЬ ПЕРЕД ИЗ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  19. ПЕЧАТЬ ‘EMP_ID:’ + + CONVERT (EMAR_MARP) (EMAR_AR_MARP) ( ‘+ @ EMP_NAME +’ EMP_SALARY ‘+ CONVERT (NVARCHAR (MAX), @ EMP_SALARY) +’ EMP_CITY ‘+ @ EMP_CITY
  20. FETCH NEXT ИЗ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_SALARY, CITY
  21. ПЕЧАТЬ ‘EMP_ID:’ + CONVERT (NVARCHAR (MAX), @ EMP_ID) + ‘EMP_NAME’ + @ EMP_NAME + ‘EMP_SALARY’ + CONVERT (NVARCHAR (MAX), @ EMP_SALARY) + ‘EMP_CITY’ + @ EMP_ITY
  22. ЗАКРЫТЬ EMP_CURSOR
  23. DEALLOCATE EMP_CURSOR
Выходной

    EMP_ID: 4 EMP_NAME Санджив EMP_SALARY 24000 EMP_CITY Алвар
    EMP_ID: 3 EMP_NAME Сандип EMP_SALARY 25000 EMP_CITY Алвар
    EMP_ID: 1 EMP_NAME Панкай EMP_SALARY 25000 EMP_CITY Алвар
    EMP_ID: 7 EMP_NAME Omi EMP_SALARY 23000 EMP_CITY Alwar
    EMP_ID: 6 EMP_NAME Naru EMP_SALARY 20000 EMP_CITY Alwar
    EMP_ID: 7 EMP_NAME Omi EMP_SALARY 23000 EMP_CITY Alwar

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

9285, например,

.Этот пример содержит все шесть режимов прокрутки (ПЕРВЫЙ, ПОСЛЕДНИЙ, ПРИОРНЫЙ, СЛЕДУЮЩИЙ, ОТНОСИТЕЛЬНЫЙ и АБСОЛЮТНЫЙ).

Пример 3 (СТАТИЧЕСКИЙ КУРСОР)

  1. SET NOCOUNT ON
  2. DECLARE @EMP_ID INT
  3. DECLARE @EMP_NAME NVARCHAR (MAX)
  4. DECLARE @ARARZEMAR DEMAR DEMARSEMAR
  5. DECLARE @AREJEMAR DEMAR INTEL
  6. ОБЪЯВИТЬ EMP_CURSOR CURSOR
  7. СТАТИЧЕСКИЙ ДЛЯ
  8. ВЫБРАТЬ * ОТ СОТРУДНИКА
  9. ОТКРЫТЬ EMP_CURSOR
  10. ВЫБРАТЬ СЛЕДУЮЩУЮ ОТ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ 900P_100B =
    = EMP_SALITY @ 900P = 1818 = 181800000000 = @ EMP_SALGING =
    = EMP_SALITY =
    EMP_SHILING
  11. EMP_SHING EMP_SHILING

  12. DECLARE EMP_CURSOR CURSOR
  13. STATIC FOR
  14. SELECT * FROM Employee
  15. Если @ EMP_ID% 2 = 0
  16. НАЧАТЬ
  17. ПЕЧАТЬ ‘EMP_ID:’ + CONVERT (NVARCHAR (MAX), @ EMP_ID) + ‘EMP_NAME’ + @ EMP_NAME + ‘EMP_SALARY’ + CONVERT (NVARCHAR (MAX), @ EMP_SALARY) + ‘EMP_CITY’ + @ EMP_CITY
  18. КОНЕЦ
  19. ВЫБРАТЬ ИЗ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  20. END
  21. ЗАКРЫТЬ EMP_CURSOR
  22. DEA LLOCATE EMP_CURSOR

Выходной

90 278

EMP_ID: 2 EMP_NAME Рахул EMP_SALARY 26000 EMP_CITY Алвар
EMP_ID: 4 EMP_NAME Санджив EMP_SALARY 24000 EMP_CITY Алвар
EMP_ID: 6 EMP_NAME Нару EMP_SALARY 20000 EMP_CITY Алвар

Пример 4.

  1. УСТАНАВЛИВАЕТСЯ НА БЕЗ
  2. ОБЪЯВЛЯЕТСЯ @EMP_ID INT
  3. ОБЪЯВЛЯЕТСЯ @EMP_NAME NVARCHAR (МАКС.)
  4. ОБЪЯВЛЯЕТСЯ @EMP_SALARY INT
  5. УМЕНЬШАЕТСЯ @EMP_CITY NVARCHAR (МАКС)
  6. УНИВЕРМАГИЯ

    817181700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008 С МУЗЕЙКОЙ ЭЛ. ОТ сотрудника
  7. ОТКРЫТЬ EMP_CURSOR
  8. ВЫБРАТЬ СЛЕДУЮЩУЮ ОТ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  9. WHILE @@ FETCH_STATUS = 0
  10. 900EG BEGIN
  11. 2% от ВНП =
  12. 07017 017000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000? + В ВНУТРЕННЕЕ ВРЕМЯ =0000000000000000000017000000000000000000000000000000000000000000000000000000000000000000] »В случае сотрудника Сотрудник SET Emp_Salary = 15000 ГДЕ ТЕКУЩИЙ EMP_CURSOR 9 0017 END
  13. FETCH FROM EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  14. END
  15. ЗАКРЫТЬ EMP_CURSOR
  16. DEALLOCATE EMP_CURSOR
, уровень 9 0 9 0 9 0 9 0 9 0 9 0 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 8 8 9 9 9 9 9 9 9 9 9 9 9 8 8 0 8 27 9 298 8 Курсор только для чтения.
Заявление было прекращено.
Сообщение 16929, уровень 16, состояние 1, строка 16
Курсор только для чтения.
Заявление было прекращено.
Сообщение 16929, уровень 16, состояние 1, строка 16
Курсор только для чтения.
Заявление было прекращено.

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

Пример 5 (ДИНАМИЧЕСКИЙ КУРСОР)

  1. SET NOCOUNT ON
  2. DECLARE @EMP_ID INT
  3. DECLARE @EMP_NAME NVARCHAR (MAX)
  4. ВНУТРЕННИЙ ДИЛ.
  5. DECLARE CURSOR EMP_CURSOR
  6. DYNAMIC ДЛЯ
  7. SELECT * FROM Employee
  8. ОТКРЫТЫЙ EMP_CURSOR
  9. FETCH СЛЕДУЮЩИЙ ИЗ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  10. WHILE @@ FETCH_STATUS = 0
  11. НАЧАТЬ
  12. , если @ EMP_ID% 2 = 0
  13. НАЧАЛО
  14. ОБНОВЛЕНИЕ Сотрудник SET Emp_Salary = 15000 ГДЕ ТЕКУЩИЙ EMP_CURSOR
  15. КОНЕЦ
  16. ВЫБОР ИЗ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME 9002, EMP_SEME @ EMP_SAL, @ EMP_SEE
  17. DEALLOCATE EMP_CURSOR
  18. ВЫБРАТЬ * ОТ сотрудника

90 023 Выход

Output

Пример 6

  1. SET NOCOUNT ON
  2. DECLARE @EMP_ID INT
  3. DECLARE @EMP_NAME NVARCHAR (MAX)
  4. DEMAR 9002 9001 DEMP DECE 9002 MAX)
  5. DECLARE CURSOR EMP_CURSOR
  6. FAST_FORWARD ДЛЯ
  7. SELECT * FROM Employee
  8. ОТКРЫТЫЙ EMP_CURSOR
  9. FETCH СЛЕДУЮЩИЙ ИЗ EMP_CURSOR INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  10. WHILE @@ FETCH_STATUS = 0
  11. НАЧАЛО
  12. Если @ EMP_ID% 2 = 0
  13. НАЧАЛО
  14. ОБНОВЛЕНИЕ Сотрудник SET Emp_Salary = 15000 ГДЕ ТЕКУЩИЙ EMP_CURSOR
  15. КОНЕЦ
  16. ВЫБОР ИЗ EMP_CURSOR INTO @EMP_ID 900 @ EMP_NAME, EMP_NAME, EMP_NAME
  17. ЗАКРЫТЬ EMP_CURSOR
  18. СДЕЛАТЬ EMP_CURSOR
Outpu t

    Msg 16929, уровень 16, состояние 1, строка 16
    Курсор только для чтения.
    Заявление было прекращено.
    Сообщение 16929, уровень 16, состояние 1, строка 16
    Курсор только для чтения.
    Заявление было прекращено.
    Сообщение 16929, уровень 16, состояние 1, строка 16
    Курсор только для чтения.
    Заявление было прекращено.

FAST_FORWARD курсор также читается как статический курсор. Мы не можем изменять данные в курсоре FAST_FORWARD.

Пример 7

  1. УСТАНОВИТЬ NOCOUNT ON
  2. ОБЪЯВИТЬ @EMP_ID INT
  3. ОБЪЯВИТЬ @EMP_NAME NVARCHAR (МАКС.)
  4. ДЕКАРЕЙ @EMP_SALARY INT
  5. УТВАРЬ CURSOR
  6. KEYSET scroll
  7. ДЛЯ
  8. ВЫБРАТЬ EMP_ID, EMP_NAME, EMP_SALARY, EMP_CITY FROM для заказа сотрудника по Emp_Id
  9. ОТКРЫТЬ EMP_CURSOR1
  10. IF @@ CURSOR_ROWS @ 9001 ИМХОМП ФИГОР-НЕТ> 0
  11. 900 ЭМП-ЗЕМЛЯ ИЗ ФИЛЬМА , @ EMP_SALARY, @ EMP_CITY
  12. WHILE @@ FETCH_STATUS = 0
  13. НАЧАТЬ
  14. Если @ EMP_ID% 2 = 0
  15. ОБНОВЛЕНИЕ Сотрудник SET EMP_NAME = ‘Панкай КУМАР Чудхари’ WHERE CURRENT OF EMP_CURSOR1
  16. FETCH затем от EMP_CURSOR1 INTO @EMP_ID, @ EMP_NAME, @ EMP_SALARY, @ EMP_CITY
  17. END
  18. END 9 0018
  19. ЗАКРЫТЬ EMP_CURSOR1
  20. DEALLOCATE EMP_CURSOR1
  21. SET NOCOUNT OFF
  22. SELECT * FROM Employee

Выход

result

Резюме

В этой статье мы узнали о курсоров в SQL.Мы узнали о типах курсоров SQL, о том, как написать курсор в SQL и выполнить его.

SQL Server курсор учебник

Введение

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

Транзакционное и процедурное программирование

SQL Server — это система управления реляционными базами данных (RDBMS), а T-SQL — это язык транзакционного программирования. Это означает, что он предназначен для выполнения своей работы в режиме «все или ничего». Механизм базы данных оптимизирован для работы таким образом, и, как правило, его более чем достаточно для выполнения простых транзакций типа «все в одном».

Многие другие языки программирования, включая C # и Visual Basic, являются итеративными или процедурными языками программирования, в которых общий поток вещей заключается в том, чтобы обрабатывать каждый экземпляр объекта по отдельности, а при работе со многими объектами можно стремиться перебирать один и тот же код, пока стек не станет уменьшено и обработано.

Тем не менее, курсоры

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

В мире IT Engineering люди обычно изучают такие языки, как C #, VB, java, C ++ или любые другие другие языки итеративного типа, прежде чем им приходится иметь дело с SQL любым реальным / продвинутым способом. Именно по этой причине, к сожалению, курсоры SQL Server часто очень плодотворны в некоторых приложениях.Это обычная ловушка, в которую попадают разработчики по уважительной причине. Логика, лежащая в основе курсоров, может быть идеальной, и идея написания одного может показаться хорошей, но возникает проблема, связанная с производительностью, поскольку SQL Server больше не собирается обрабатывать целые порции данных сразу, а вместо этого должен повторять операции чтения и записи. для каждого результата (который может быть катастрофическим для производительности ввода / вывода)

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

Однако в некоторых ситуациях курсоры могут быть спасителями.Я могу думать о паре сразу же:

  1. Параллельные запросы: иногда в системах OLTP (OnLine Transaction Processing) слишком много пользователей активно запрашивают определенную таблицу. Это нормально для небольших транзакций, поскольку они молниеносны и не требуют блокировок для больших кусков базовых таблиц. Но для того, чтобы иметь возможность обновлять всю таблицу, SQL Server часто приходится создавать огромную блокировку, которая блокирует все другие действия в той же таблице. Это для того, чтобы защитить согласованность данных.Если бы это было не так, можно было бы использовать параллельное использование и ВЫБРАТЬ строки из таблицы, которые наполовину обновлены и наполовину не обновлены. Существуют параметры уровня сервера для обработки типа обязательств чтения, они называются уровнями изоляции транзакций и выходят за рамки этой статьи. Однако, если у вас есть уровень изоляции транзакции READ COMMITTED, который имеет место по умолчанию, курсоры SQL Server или циклы while могут быть полезны для разбиения полных обновлений таблиц на несколько меньших пакетов.
  2. Второй случай, когда курсоры могут быть полезны, — это создание логики типа «для каждого» в сценариях T-SQL. Например, если вы хотите обработать развертывание отдельных таблиц в другой базе данных, можно использовать курсор и sp_executeSql для запуска фрагмента T-SQL для каждой таблицы в заданном списке.

В приведенном ниже примере мы пройдемся по содержимому таблицы и выберем описание каждого найденного нами идентификатора.

Возьмем эту простую таблицу в качестве примера:

CREATE TABLE #ITEMS (уникальный идентификатор ITEM_ID NOT NULL, ITEM_DESCRIPTION VARCHAR (250) NOT NULL)

ВСТАВИТЬ В #ITEMS

ЗНАЧЕНИЯ

(NEWID (), ‘Это замечательный автомобиль’),

(NEWID 9 (

) (

), «Это быстрый велосипед»),

(NEWID (), «Это дорогой самолет»),

(NEWID (), «Это дешевый велосипед»),

(NEWID (), «Это праздник мечты»)

Вот результаты запроса SELECT * FROM #ITEMS:

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

1

2

3

4

5

6

7

8

9

10

11

12

140007

140007000000000

18

19

20

21

22

23

24

DECLARE @ITEM_ID uniqueidentifier — Здесь мы создаем переменную, которая будет содержать идентификатор каждой строки.

DECLARE ITEM_CURSOR CURSOR — Здесь мы подготавливаем курсор и даем оператор SELECT для перебора

FOR

SELECT ITEM_ID

ОТ #ITEMS

ОТКРЫТЫЙ ITEM_CURSOR

00 результатов ОТЗЫВОМ

в память — Это

FETCH NEXT ИЗ ITEM_CURSOR INTO @ITEM_ID — Мы выбираем первый результат

WHILE @@ FETCH_STATUS = 0 — Если выборка прошла хорошо, тогда мы идем на это

НАЧИНАЕМ

НАЗВАНИЕ

_000C ВЫБОР оператор выбора (здесь вы можете выполнять любую работу, какую пожелаете)

ОТ #ITEMS

ГДЕ ITEM_ID = @ITEM_ID — в отношении нашего последнего извлеченного идентификатора

ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ ITEM_CURSOR INTO @ITEM_ID — После выполнения работы Готово, мы получаем следующий результат. 007

DEALLOCATE ITEM_CURSOR — ЗАКРЫТЬ и DEALLOCATE удалить данные из памяти и очистить процесс

Запуск базового курсора SQL Server, приведенного выше, будет циклически проходить через каждый идентификатор в таблице #ITEMS и ВЫБРАТЬ его соответствующий ITEM_DESCRIPTION в 5 отдельных транзакциях.Вы должны получить следующие результаты после выполнения курсора:

Этот пример может показаться бессмысленным, но примите во внимание тот факт, что вы можете написать любой T-SQL, который вам нравится, между

WHILE @@ FETCH_STATUS = 0

НАЧАЛО

… и…

ПОЛУЧИТЬ СЛЕДУЮЩУЮ ОТ [CursorName]

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

Заключение

Эта статья не предназначена для более широкого использования курсоров SQL Server в ваших приложениях. Как общее практическое правило, нужно всегда думать дважды, даже трижды, приемлемо ли использование курсора для их текущей проблемы. В 99% случаев эту проблему можно решить чисто транзакционным способом, как это принято в T-SQL. Однако, как упомянуто выше, существуют определенные исключения из этого правила, когда становится совершенно приемлемым жертвовать производительностью, чтобы избежать блокировки приложения, или просто потому, что другого варианта нет (это очень редко встречается в ИТ).

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

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

Просмотреть все сообщения от Evan Barke

Последние сообщения от Evan Barke (просмотреть все) ,Курсоры
В SQL Server Курсор

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

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

  1. Объявление курсора

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

  2. Открыть

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

  3. Fetch

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

  4. Закрыть

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

  5. Deallocate

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

Синтаксис объявления курсора

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

 ОБЪЯВЛЯЕТ имя курсора CURSOR
 [МЕСТНЫЙ | GLOBAL] - определить область действия курсора
 [FORWARD_ONLY | SCROLL] - определить движения курсора (вперед / назад)
 [СТАТИЧЕСКИЙ | KEYSET | ДИНАМИЧНЫЙ | FAST_FORWARD] - основной тип курсора
 [READ_ONLY | SCROLL_LOCKS | OPTIMISTIC] - определить замки
 FOR select_statement --define оператор SQL Select
 FOR UPDATE [col1, col2, ... coln] - определить столбцы, которые необходимо обновить 

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

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

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

Синтаксис для извлечения курсора

Оператор Fetch предоставляет множество опций для извлечения строк из курсора. NEXT — опция по умолчанию. Основной синтаксис для извлечения курсора приведен ниже:

 FETCH [СЛЕДУЮЩАЯ | ПРИОРНАЯ | ПЕРВЫЙ | ПОСЛЕДНЯЯ | АБСОЛЮТНАЯ n | ОТНОСИТЕЛЬНАЯ n]
FROM [GLOBAL] имя_курсора
INTO @Variable_name [1,2, .. n] 

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

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

 ЗАКРЫТЬ имя_ курсора - после закрытия его можно открыть заново. 

Синтаксис для освобождения курсора

Оператор Deallocate удаляет определение курсора и освобождает все системные ресурсы, связанные с курсором. Базовый синтаксис для закрытия курсора приведен ниже:

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

СЕРВЕР SQL — Простые примеры курсоров

 CREATE TABLE Сотрудник
(
 EmpID в первичном ключе,
 EmpName varchar (50) NOT NULL,
 Зарплата int NOT NULL,
 Адрес varchar (200) НЕ NULL,
)
ИДТИ
INSERT INTO Employee (EmpID, EmpName, Salary, Address) ЗНАЧЕНИЯ (1, «Мохан», 12000, «Нойда»)
INSERT INTO Сотрудник (EmpID, EmpName, Зарплата, Адрес) ЦЕННОСТИ (2, «Паван», 25000, «Дели»)
INSERT INTO Сотрудник (EmpID, EmpName, Зарплата, Адрес) ЦЕННОСТИ (3, «Амит», 22000, «Дехрадун»)
INSERT INTO Сотрудник (EmpID, EmpName, Зарплата, Адрес) ЦЕННОСТИ (4, «Сону», 22000, «Нойда»)
INSERT INTO Сотрудник (EmpID, EmpName, Зарплата, Адрес) ЦЕННОСТИ (5, «Дипак», 28000, «Гургаон»)
ИДТИ
SELECT * FROM Employee 
 SET NOCOUNT ON
ОБЪЯВИТЬ @Id int
ОБЪЯВИТЬ @ name varchar (50)
ОБЪЯВИТЬ @salary int
 ОБЪЯВИТЬ cur_emp CURSOR
СТАТИЧЕСКИЙ ДЛЯ
ВЫБЕРИТЕ EmpID, EmpName, Зарплату от Сотрудника
OPEN cur_emp
IF @@ CURSOR_ROWS> 0
 НАЧАТЬ
 ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ cur_emp INTO @ Id, @ name, @ salary
 WHILE @@ Fetch_status = 0
 НАЧАТЬ
 ПЕЧАТЬ 'ID:' + convert (varchar (20), @ Id) + ', Name:' + @ name + ', Salary:' + convert (varchar (20), @ salary)
 ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ cur_emp INTO @ Id, @ name, @ salary
 КОНЕЦ
КОНЕЦ
ЗАКРЫТЬ cur_emp
DEALLOCATE cur_emp
ВЫКЛЮЧИТЕ NOCOUNT 

Подробнее Статьи, относящиеся к LINQ

Резюме

В этой статье я попытаюсь объяснить основы Cursor в SQL Server на простом примере.Я надеюсь, что после прочтения этой статьи вы сможете понять курсоры в SQL Server. Здесь также я хотел бы поделиться связанной статьей Альтернативы курсора SQL Server. Я хотел бы получить обратную связь от моих читателей блога. Пожалуйста, оставьте свой отзыв, вопрос или комментарий об этой статье.

Поделиться Артикул

Пройдите наши бесплатные тесты навыков, чтобы оценить свои навыки!

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

Курсор в SQL | Неявные и явные курсоры с примерами

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

Ниже приведены темы, которые я буду обсуждать в этой статье:

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

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

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

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

SQL предоставляет два типа курсоров, которые я перечислил ниже:

  1. Неявный курсор

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

Атрибут Описание
% FOUND Будет возвращено значение ИСТИНА, если оператор INSERT, UPDATE или DELETE воздействует на одну или несколько строк или инструкция SELECT INTO возвращает одну или несколько строк. ,В других случаях он вернет FALSE.
% NOTFOUND Это технически противоположно атрибуту% FOUND. Он возвращает TRUE, если оператор INSERT, UPDATE или DELETE не влияет на строки или оператор SELECT INTO не возвращает строк. Иначе это возвращает просто ЛОЖЬ.
% ISOPEN Этот атрибут всегда будет возвращать FALSE для неявных курсоров, поскольку курсор SQL автоматически закрывается сразу после выполнения соответствующего оператора SQL.
% ROWCOUNT Возвращает общее количество строк, затронутых оператором INSERT, UPDATE или DELETE, или строк, возвращаемых оператором SELECT INTO.

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

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

Синтаксис SQL-курсора

Ниже приведен общий синтаксис для создания явного курсора.

 CURSOR cursorName IS selectStatement; 

Здесь:

cursorName — Это представляет действительное имя для курсора.

selectStatement — Это представляет запрос на выборку, который возвратит несколько строк.

Давайте теперь продолжим эту статью и посмотрим на жизненный цикл курсора SQL.

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

Существуют в основном 5 этапов жизненного цикла курсора в SQL, которые я перечислил ниже:

  1. Объявить
 ОБЪЯВИТЬ курсораИмя курсора
FOR selectStatement; 

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

  1. Открыть
 OPEN cursorName; 

Этот шаг позволит вам открыть и заполнить курсор, выполнив его.

  1. Fetch
 FETCH NEXT FROM курсора INTO variableList; 

Этот шаг извлекает строку из курсора и сохраняет ее в одной или нескольких переменных.

[Необязательно] CheckStatus

 WHILE @@ FETCH_STATUS = 0
НАЧАТЬ
FETCH NEXT FROM cursorName;
КОНЕЦ; 

Эта функция возвращает состояние последнего оператора FETCH, который был выполнен для курсора. Если эта функция возвращает 0, это означает, что операция FETCH прошла успешно.Чтобы извлечь все строки из курсора, используется предложение WHILE.

  1. Закрыть
 ЗАКРЫТЬ cursorName; 

Этот шаг поможет вам закрыть курсор после завершения операций.

  1. Deallocate
 DEALLOCATE cursor_name; 

Этот шаг поможет освободить курсор и освободить пространство памяти.

На этом я хотел бы завершить эту статью о курсоре в SQL.Я надеюсь, что эта статья помогла вам повысить ценность ваших знаний. Для получения дополнительной информации о SQL или Базы данных, вы можете обратиться к нашему полному списку чтения здесь: Базы данных Edureka .

Основы SQL для начинающих | Учиться SQL | Учебник по SQL для начинающих | Edureka

Это видеофильм Edureka «Основы SQL для начинающих» поможет вам понять основы SQL, а также запросы SQL, которые очень популярны и необходимы.

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

Есть вопрос для нас? Пожалуйста, укажите это в разделе комментариев ” Курсор в SQL ”, и я перезвоню вам.

.