3 Управління курсором в середовищі ms sql Server
Управління курсором реалізується шляхом виконання наступних команд:
DECLARE – створення або оголошення курсору ;
OPEN – відкриття курсору, тобто наповнення його даними;
FETCH – вибірка з курсору і зміна рядків даних за допомогою курсору;
CLOSE – закриття курсору ;
DEALLOCATE – звільнення курсору, тобто видалення курсору як об”єкту.
Оголошення курсору
В стандарті SQL для створення курсору передбачена наступна команда:
<створення_курсору>::=
DECLARE ім”я_курсору [INSENSITIVE][SCROLL] CURSOR
FOR SELECT_оператор
[FOR { READ_ONLY | UPDATE [Ім”я_колонки[,...n]]}]
При використовуванні ключового слова INSENSITIVE буде створений статичний курсор. Зміни даних не дозволяються, крім того, не відображаються зміни, зроблені іншими користувачами. Якщо ключове слово INSENSITIVE відсутнє, створюється динамічний курсор.
При вказівці ключового слова SCROLL створений курсор можна прокручувати в будь-якому напрямі, що дозволяє застосовувати будь-які команди вибірки. Якщо цей аргумент опускається, то курсор виявиться послідовним, тобто його перегляд буде можливий тільки в одному напрямі – від початку до кінця.
SELECT-оператор задає тіло запиту SELECT, за допомогою якого визначається результуючий набір рядків курсору.
При вказівці аргументу FOR READ_ONLY створюється курсор "тільки для читання", і ніякі модифікації даних не дозволяються. Він відрізняється від статичного, хоча останній також не дозволяє міняти дані. Як курсор "тільки для читання" може бути оголошений динамічний курсор, що дозволить відображати зміни, зроблені іншим користувачем.
Створення курсору з аргументом FOR UPDATE дозволяє виконувати в курсорі зміну даних або у вказаних стовпцях, або, за відсутності аргументу ім”я_колонки, у всіх стовпцях.
В середовищі MS SQL Server прийнятий наступний синтаксис команди створення курсору:
<створення_курсору>::=
DECLARE ім”я_курсору CURSOR [LOCAL | GLOBAL]
[FORWARD_ONLY | SCROLL]
[STATIC | KEYSET | DYNAMIC | FAST_FORWARD]
[READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]
[TYPE_WARNING]
FOR SELECT_оператор
[FOR UPDATE [Ім”я_колонки[,...n]]]
При використанні ключового слова LOCAL буде створений локальний курсор, який видний тільки в межах пакету, тригера, збереженої процедури або призначеної для користувача функції, що створив його. Після закінчення роботи пакету, тригера, процедури або функції курсор неявно знищується. Щоб передати вміст курсору за межі конструкції, що створила його, необхідно привласнити його параметру аргумент OUTPUT.
Якщо вказано ключове слово GLOBAL, створюється глобальний курсор ; він існує до закриття поточного з’єднання.
При вказівці FORWARD_ONLY створюється послідовний курсор ; вибірку даних можна здійснювати тільки в напрямі від першого рядка до останнього.
При вказівці SCROLL створюється прокручуваний курсор ; звертатися до даних можна у будь-якому порядку і в будь-якому напрямі.
При вказівці STATIC створюється статичний курсор.
При вказівці KEYSET створюється ключовий курсор.
При вказівці DYNAMIC створюється динамічний курсор.
Якщо для курсору READ_ONLY вказати аргумент FAST_FORWARD, то створений курсор буде оптимізований для швидкого доступу до даних. Цей аргумент не може бути використаний спільно з аргументами FORWARD_ONLY і OPTIMISTIC.
В курсорі, створеному з вказівкою аргументу OPTIMISTIC, забороняється зміна і видалення рядків, які були змінені після відкриття курсору.
При вказівці аргументу TYPE_WARNING сервер інформуватиме користувача про неявну зміну типу курсору, якщо він несумісний із запитом SELECT.
Відкриття курсору
Для відкриття курсору і наповнення його даними з вказаного при створенні курсору запиту SELECT використовується наступна команда:
OPEN {{[GLOBAL]ім”я_курсору }
|@ім”я_змінної_курсору}
Після відкриття курсору відбувається виконання пов”язаного з ним оператора SELECT, вихідні дані якого зберігаються в багаторівневій пам'яті.
Вибірка даних з курсору
Відразу після відкриття курсору можна вибрати його вміст (результат виконання відповідного запиту) за допомогою наступної команди:
FETCH [[NEXT | PRIOR | FIRST | LAST
| ABSOLUTE {номер_рядка
| @змінна_номера_рядка}
| RELATIVE {номер_рядка |
@змінна_номера_рядка}]
FROM ]{{[GLOBAL ]ім”я_курсору }|
@ім”я_змінної_курсору }
[INTO @ім”я_змінної [,...n]]
При вказівці FIRST буде повернений найперший рядок повного результуючого набору курсору, який стає поточним рядком.
При вказівці LAST повертається самий останній рядок курсору. Вона ж стає поточним рядком.
При вказівці NEXT повертається рядок, що знаходиться в повному результуючому наборі зразу ж після поточної. Тепер вона стає поточною. За умовчанням команда FETCH використовує саме цей спосіб вибірки рядків.
Ключове слово PRIOR повертає рядок, що знаходиться перед поточною. Вона і стає поточною.
Аргумент ABSOLUTE {номер_рядка | @змінна_номера_рядка} повертає рядок по його абсолютному порядковому номеру в повному результуючому наборі курсору. Номер рядка можна задати за допомогою константи або як ім”я змінної, в якій зберігається номер рядка. Змінна повинна мати цілочисельний тип даних. Вказуються як позитивні, так і негативні значення. При вказівці позитивного значення рядок відлічується від початку набору, негативного – від кінця. Вибраний рядок стає поточним. Якщо вказано нульове значення, рядок не повертається.
Аргумент RELATIVE {кільк_рядка | @змінна_кільк_рядка} повертає рядок, що знаходиться через вказану кількість рядків після поточного. Якщо вказати негативне значення числа рядків, то буде повернений рядок, що знаходиться за вказану кількість рядків перед поточним. При вказівці нульового значення повернеться поточний рядок. Повернений рядок стає поточним.
Щоб відкрити глобальний курсор, перед його ім”ям вимагається вказати ключове слово GLOBAL. Ім”я курсору також може бути вказано за допомогою змінної.
В конструкції INTO @ім”я_змінної [,...n] задається список змінних, в яких будуть збережені відповідні значення стовпців рядка, що повертається. Порядок вказівки змінних повинен відповідати порядку стовпців в курсорі, а тип даних змінної – типу даних в стовпці курсору. Якщо конструкція INTO не вказана, то поведінка команди FETCH нагадуватиме поведінку команди SELECT – дані виводяться на екран.
Зміна і видалення даних
Для виконання змін за допомогою курсору необхідно виконати команду UPDATE в наступному форматі:
UPDATE ім”я_таблицы SET {ім”я_колонки = { DEFAULT | NULL | вираз}}[,...n]
WHERE CURRENT {{[GLOBAL] ім”я_курсору} |@ім”я_змінної_курсору}
За одну операцію можуть бути змінено декілька стовпців (комірок) поточного рядка курсору, але всі вони повинні належати одній таблиці.
Для видалення даних за допомогою курсору використовується команда DELETE в наступному форматі:
DELETE ім”я_таблицы
WHERE CURRENT {{[GLOBAL] ім”я_курсору} |@ім”я_змінної_курсору}
В результаті буде видалений рядок, встановлений поточним в курсорі.
Закриття курсору
CLOSE {ім”я_курсору | @ім”я_змінної_курсору}
Після закриття курсор стає неприступним для користувачів програми. При закритті знімаються всі блокування, встановлені в процесі його роботи. Закриття може застосовуватися тільки до відкритих курсорів. Закритий, але не звільнений курсор може бути повторно відкритий. Не допускається закривати невідкритий курсор.
Звільнення курсору
Закриття курсору необов'язково звільняє асоційовану з ним пам'ять. В деяких реалізаціях потрібно явним чином звільнити її за допомогою оператора DEALLOCATE. Після звільнення курсору звільняється і пам'ять, при цьому стає можливим повторне використовування імені курсору.
DEALLOCATE { ім”я_курсору | @ім”я_змінної_курсору }
Для контролю досягнення кінця курсору рекомендується застосовувати функцію: @@FETCH_STATUS
Функція @@FETCH_STATUS повертає:
-
0, якщо вибірка завершилася успішно;
-
-1, якщо вибірка завершилася невдало внаслідок спроби вибірки рядка, що знаходиться за межами курсору ;
-
-2, якщо вибірка завершилася невдало унаслідок спроби звернення до видаленого або зміненого рядка.
DECLARE abc CURSOR SCROLL FOR
SELECT * FROM Клієнт
Приклад 13.1. Оголошення курсору.
DECLARE @MyCursor CURSOR
SET @MyCursor = CURSOR LOCAL SCROLL FOR
SELECT * FROM Клієнт
Приклад 13.2. Використовування змінної для оголошення курсору.
DECLARE abc CURSOR GLOBAL SCROLL FOR
SELECT * FROM Клієнт
OPEN abc
Приклад 13.3. Оголошення і відкриття курсору.
DECLARE @MyCursor CURSOR
SET @MyCursor=abc
Приклад 13.4. Використовування змінної для переприсвоювання курсору.
Приклад 13.5. Розробити курсор для виведення списку фірм і клієнтів з Москви.
DECLARE @firm VARCHAR(50)
@fam VARCHAR(50)
@message VARCHAR(80)
PRINT « Список клієнтів”
DECLARE klient_cursor CURSOR LOCAL FOR
SELECT Фірма, Прізвище
FROM Клієнт
WHERE Місто=«Москва”
ORDER Фірма, Прізвище
OPEN klient_cursor
FETCH NEXT FROM klient_cursor INTO @firm @fam
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @message=«Клиент «+@fam+
« Фірма «+ @firm
PRINT @message
//-- перехід до наступного клієнта--
FETCH NEXT FROM klient_cursor
INTO @firm @fam
END
CLOSE klient_cursor
DEALLOCATE klient_cursor
Приклад 13.5. Курсор для виведення списку фірм і клієнтів з Москви.
Приклад 13.6. Розробити курсор для виведення списку придбаних клієнтами з Москви товарів і їх загальної вартості. В один курсор заносяться всі московські клієнти, потім для кожного рядка курсору, тобто для кожного клієнта, визначається і роздруковується інший курсор – його покупки. Підраховується загальна вартість покупок клієнта.
DECLARE @id_kl INT
@firm VARCHAR(50)
@fam VARCHAR(50)
@message VARCHAR(80)
@nam VARCHAR(50)
@d DATETIME
@p INT
@s INT
SET @s = 0
PRINT « Список покупок”
DECLARE klient_cursor CURSOR LOCAL FOR
SELECT КодКлієнта, Фірма, Прізвище
FROM Клієнт
WHERE Місто = «Москва”
ORDER Фірма, Прізвище
OPEN klient_cursor
FETCH NEXT FROM klient_cursor
INTO @id_kl @firm @fam
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @message=«Клиент”+@fam+ «Фірма”+ @firm
PRINT @message
SELECT @message=«Назва товару Дата покупки Вартість”
PRINT @message
DECLARE tovar_cursor CURSOR FOR
SELECT Товар.Назва, Операція.Дата, Товар.Цена*Операція.Кількість AS Вартість
FROM Товар INNER JOIN Операція ON Товар.КодТовара=Операція.КодТовара
WHERE Операція.КодКлиента=@id_kl
OPEN tovar_cursor
FETCH NEXT FROM tovar_cursor
INTO @nam @d @p
IF @@FETCH_STATUS<>0
PRINT «Немає покупок”
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @message=« ”+@nam+ «”+ CAST(@d AS CHAR(12))+ « ” +CAST(@p AS CHAR(6))
PRINT @message
SET @s=@s+@p
FETCH NEXT FROM tovar_cursor
INTO @nam @d @p
END
CLOSE tovar_cursor
DEALLOCATE tovar_cursor
SELECT @message=«Загальна вартість”+ CAST(@s AS CHAR(6))
PRINT @message
//-- перехід до наступного клієнта--
FETCH NEXT FROM klient_cursor
INTO @id_kl @firm @fam
END
CLOSE klient_cursor
DEALLOCATE klient_cursor
Приклад 13.6. Курсор для виведення списку придбаних клієнтами з Москви товарів і їх загальної вартості.
Приклад 13.7. Розробити прокручуваний курсор для клієнтів з Москви. Якщо номер телефону починається на 1, видалити клієнта з таким номером і в першому записі курсору замінити першу цифру в номері телефону на 4.
DECLARE @firm VARCHAR(50)
@fam VARCHAR(50)
@tel VARCHAR(8)
@message VARCHAR(80)
PRINT «Список клієнтів”
DECLARE klient_cursor CURSOR GLOBAL SCROLL
KEYSET FOR
SELECT Фірма, Прізвище, Телефон
FROM Клієнт
WHERE Місто = «Москва”
ORDER Фірма, Прізвище
FOR UPDATE
OPEN klient_cursor
FETCH NEXT FROM klient_cursor
INTO @firm @fam @tel
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @message=«Клиент” +@fam+«Фірма”+@firm «Телефон”+ @tel
PRINT @message
//-- якщо номер телефону починається на 1
//-- видалити клієнта з таким номером
IF @tel LIKE «1%”
DELETE Клієнт
WHERE CURRENT klient_cursor
ELSE
//-- перехід до наступного клієнта
FETCH NEXT FROM klient_cursor
INTO @firm @fam @tel
END
FETCH ABSOLUTE 1 FROM klient_cursor
INTO @firm @fam @tel
//-- в першому записі замінити першу цифру в
//-- номері телефону на 4
UPDATE Клієнт SET Телефон=«4” +
RIGHT(@tel,LEN(@tel)-1))
WHERE CURRENT klient_cursor
SELECT @message=«Клиент”+@fam+ «Фірма”+@firm «Телефон”+ @tel
PRINT @message
CLOSE klient_cursor
DEALLOCATE klient_cursor
Приклад 13.7. Прокручуваний курсор для клієнтів з Москви.
Приклад 13.8. Використовування курсору як вихідного параметра процедури. Процедура повертає набір даних – список товарів.
CREATE PROC my_proc
@cur CURSOR VARYING OUTPUT
AS
SET @cur=CURSOR FORWARD_ONLY STATIC FOR
SELECT Назва FROM Товар
OPEN @cur
Приклад 13.8. Використовування курсору як вихідного параметра процедури.
Виклик процедури і вивыд на друк даних з вихідного курсору здійснюється таким чином:
DECLARE @my_cur CURSOR
DECLARE @n VARCHAR(20)
EXEC my_proc @cur=@my_cur OUTPUT
FETCH NEXT FROM @my_cur INTO @n
SELECT @n
WHILE (@@FETCH_STATUS=0)
BEGIN
FETCH NEXT FROM @my_cur INTO @n
SELECT @n
END
CLOSE @my_cur
DEALLOCATE @my_cur
Контрольні питання
-
Дайте визначення курсору. В чому полягає його основне призначення?
-
Яким чином робота з пам’яттю пов’язана з курсорами?
-
Які дії можна виконати над курсорами?
-
Які типи курсорів ви можете назвати?
-
В чому особливість роботи і призначення послідовних курсорів? Де вони застосовні?
-
В чому особливість роботи і призначення прокручуваних курсорів? Де вони застосовні?
-
Поясніть принцип роботи і призначення статичних курсорів.
-
Поясніть принцип роботи і призначення динамічних курсорів.
-
Поясніть принцип роботи і призначення послідовних курсорів.
-
Поясніть принцип роботи і призначення курсорів, керованих набором ключів.
-
Яким чином реалізується управління курсором в середовищі MS SQL Server?
-
Які параметри та команди за яку дію відповідають?
-
Як оголошується курсор? Поясніть синтаксис команди.
-
Як створюється курсор? Поясніть синтаксис команди.
-
Як відкривається курсор? Поясніть синтаксис команди.
-
Як здійснюється вибірка даних з курсору? Поясніть синтаксис команди.
-
Як здійснюється зміна даних в курсорі? Поясніть синтаксис команди.
-
Як здійснюється видалення даних з курсору? Поясніть синтаксис команди.
-
Як здійснюється закриття курсору? Поясніть синтаксис команди.
-
Як здійснюється звільнення курсору? Поясніть синтаксис команди.
