
- •ПоСіБник до вивчення курсу «оргаНізація баз даних»
- •Лабораторна робота № 1 Інсталяція та інтерфейс Microsoft sql Server
- •Завдання для самостійної роботи
- •Лабораторна робота № 2 Розробка реляційної бази даних
- •Завдання
- •Лабораторна робота № 3 Створення та наповнення таблиць бд
- •Теоретична частина
- •Insert into persons values ('ivanov', 'ivan', 'ivanovich')
- •Insert into persons values ('petrov', 'petr', 'petrovich')
- •Insert into persons values ('sidorov', 'sidor', 'sidorovich')
- •Id_pers int not null references persons)
- •Insert into students values (9560679, @id_pr)
- •Insert into students values (3945794, @id_pr)
- •Insert into students values (4596956, @id_pr)
- •Id_subj int references subjects,
- •Id_mark int references marks)
- •Insert into stud_progress(id_stud, id_subj, id_mark) values
- •Insert into stud_progress(id_stud, id_subj, id_mark) values
- •Insert into stud_progress(id_stud, id_subj, id_mark) values
- •Завдання
- •Лабораторна робота № 4 Виконання запитів до бази даних
- •Теоретична частина
- •Into ім'я_таблиці
- •In (список_імен_стовпців_значень_груп)
- •In (список_імен_стовпців))
- •Intersect
- •Intersect
- •Лабораторна робота № 5 Ітеративна обробка результату запита
- •Теоретична частина
- •5.1. Declare
- •5.2. Open
- •5.3. Fetch
- •5.4. Close
- •5.5. Deallocate
- •5.6. Функції роботи з курсорами
- •5.7. Приклади використання курсорів
- •Завдання
- •Лабораторна робота № 6 Створення тригерів бд
- •Теоретична частина.
- •Видалення тригерів.
- •Дозвіл | заборона спрацьовування тригерів.
- •Приклади тригерів.
- •Instead of delete
- •Instead of insert, update, delete
- •Insert into table1(c1, c2) (select c1, c2 from inserted)
- •Завдання.
5.5. Deallocate
Видаляє посилання на зазначений курсор. Коли останнє посилання на курсор видаляється, то це приводить до видалення всіх структур даних, використовуваних курсором. Може застосовуватися без команди CLOSE. Ця команда має наступний синтаксис:
DEALLOCATE {[GLOBAL] <ім'я курсору> | @cursor_variable},
де ключове слово GLOBAL показує, що курсор з іменем <ім'я курсору> є глобальним.
5.6. Функції роботи з курсорами
@@CURSOR_ROWS - повертає кількість рядків, що містяться в останньому відкритому в поточному з'єднанні курсорі. Може повернути такі значення:
деяке від’ємне число. Показує, що цей курсор наповнюється даними асинхронно. Може мати місце для більших KEYSET або STATIC курсорів.
-1. Повертається для динамічного курсору (DYNAMIC). Оскільки цей курсор відображає всі зміни у вихідних даних, то кількість рядків, що містяться в ньому, невідомо.
0. Курсор ще не відкритий, уже закритий або жоден рядок для нього не обраний.
Деяке позитивне число. Кількість рядків, витягнутих у курсор.
CURSOR_STATUS({{'local' | 'global'}, 'ім'я курсору' | 'variable', '@cursor_var'}) - повертає стан курсору. Має 2 строкових аргументи: 1-ий має значення 'local' або 'global' для курсорів, заданих ім'ям ( 2-ий параметр) або 'variable' - для курсорів заданих змінною ( 2-ий параметр). Може повертати наступні значення:
1. Показує, що цей курсор відкритий і має хоча б 1 рядок (для DYNAMIC курсорів 0 або більше рядків).
0. Курсор відкритий, але не містить рядків. Це значення не може бути повернуте для DYNAMIC курсорів.
-1. Курсор закритий.
-2. Може бути повернуто, якщо курсор заданий змінною. Означає, що курсор не пов'язаний зі змінною.
-3. Такого курсору або змінної не існує або змінна існує, але не пов'язана з курсором.
@@FETCH_STATUS - повертає результат виконання останньої команди FETCH (ціле число):
0. Команда FETCH виконана успішно.
-1. Команда FETCH не могла бути виконана успішно або заданий рядок виходить за межі наявної множини рядків.
-2. Рядок, що витягається, відсутній.
5.7. Приклади використання курсорів
Всі приклади роботи з курсорами будуть побудовані з використанням таблиці table1, що створена в такий спосіб:
declare
@var varchar(128)
set @var = 'table1'
if exists (select table_name from information_schema.tables where table_name = @var)
execute ('drop table ' + @var)
execute ('create table ' + @var + ' ( c1 int, c2 int, c3 int primary key identity ) ')
execute ('insert into ' + @var + '(c1, c2) values (1, 2)')
execute ('insert into ' + @var + '(c1, c2) values (1, 2)')
execute ('insert into ' + @var + '(c1, c2) values (1, 2)')
execute ('insert into ' + @var + '(c1, c2) values (1, 2)')
execute ('insert into ' + @var + '(c1, c2) values (2, 5)')
execute ('insert into ' + @var + '(c1, c2) values (6, 5)')
execute ('insert into ' + @var + '(c1, c2) values (2, 4)')
execute ('insert into ' + @var + '(c1, c2) values (2, 3)')
go
Приклад 1.
/*
Перевіряємо існування описуваного курсору за допомогою функції cursor_status. Якщо курсор існує, то виконуємо стосовно нього команду DEALLOCATE
*/
if (cursor_status('global', 'cursor1') <> -3)
deallocate global cursor1
/*
Створюємо глобальний курсор, що має властивості FORWARD_ONLY, DYNAMIC, OPTIMISTIC, обрані за замовчуванням. Відповідний запит SELECT вибирає значення стовпців c1, c2 з тих рядків, у яких поле c1 лежить на відрізку [2..4].
*/
declare cursor1 cursor
global
for select c1, c2 from table1 where c1 between 2 and 4
/*
Виконуємо команду примусового завершення транзакції. Після неї всі оголошені змінні, локальні курсори стають недоступні.
*/
go
/*
Описуємо змінну типу курсор і ставимо їй у відповідність глобальний курсор cursor1
*/
declare @cursor cursor
set @cursor = cursor1
/*
Відкриваємо курсор.
*/
open @cursor
/*
Витягаємо 1-ий рядок з курсору (використовуючи опцію за замовчуванням NEXT).
*/
fetch @cursor
/*
Оскільки всі описані до виконання команди go змінні більше недоступні, то знову описуємо строкову змінну і поміщаємо в неї ім'я тестової таблиці. Використовуючи цю змінну і команду UPDATE, змінюємо значення стовпця c2 в обраному рядку. Рядок задається за допомогою конструкції WHERE CURRENT OF <ім'я курсору>, що вказує на той рядок таблиці, що є поточним рядком для курсору.
Після зазначеної зміни за допомогою команди SELECT виводимо всі значення стовпців c1, c2, які належать рядкам, що задовольняють наступній умові: значення поля c1 лежать на відрізку [2..4].
*/
declare @var varchar(128)
set @var = 'table1'
execute ('update ' + @var + ' SET c2 = 3 where current of cursor1')
execute ('select c1, c2 from ' + @var + ' where c1 between 2 and 4')
/*
Оскільки курсор динамічний, то він відображає всі зміни, зроблені в базовій таблиці. Таким чином, виконавши наступну команду UPDATE, що змінює значення стовпця c2 у тому рядку, де c2 був рівним 4, ми можемо в цьому переконатися, послідовно витягаючи в циклі WHILE всі рядки з описаного курсору. Цикл працює, поки функція @@FETCH_STATUS видає значення відмінні від -1, тобто рядок, що витягається, не вийшов за межі діапазону. Такий цикл застосуємо, тому що курсор динамічний (значення -2 повернуте не буде).
*/
execute ('update ' + @var + ' SET c2 = 13 where c2 = 4')
while @@FETCH_STATUS <> -1
begin
fetch next from @cursor
end
/*
Закриваємо курсор.
*/
close @cursor
Приклад 2.
/*
Перевіряємо існування описуваного курсору за допомогою функції cursor_status. Якщо курсор існує, то виконуємо стосовно нього команду DEALLOCATE
*/
if (cursor_status('global', 'cursor2') <> -3)
deallocate global cursor2
/*
Створюємо глобальний курсор, що має властивості SCROLL, KEYSET, зазначені явно, і властивість OPTIMISTIC, обрану за замовчуванням. Відповідний запит SELECT вибирає значення стовпців c1, c2 з тих рядків, у яких поле c1 лежить на відрізку [2..4].
*/
declare cursor2 cursor
global
scroll
keyset
for select c1, c2 from table1 where c1 between 2 and 4
/*
Відкриваємо курсор.
*/
open cursor2
/*
Оскільки всі описані до виконання команди go змінні більше недоступні, то знову описуємо строкову змінну і 3 допоміжні цілочисельні змінні і поміщаємо в строкову змінну ім'я тестової таблиці.
Використовуючи цю змінну і команду DELETE, видаляємо рядок таблиці, що має значення стовпця c2 = 4.
*/
declare @var varchar(128),
@c1 int,
@c2 int,
@fetch_res int
set @var = 'table1'
execute ('delete ' + @var + ' where c2 = 4')
/*
Цикл, що здійснював у минулому прикладі черговий вибір всіх рядків з курсору, у загальному випадку не дуже вдалий, тому що має наступні недоліки:
Потрібне первісне добування рядка перед циклом.
Розглядається тільки 1 варіант невдалої вибірки (функція повертає -1). Якщо ж буде спроба вибірки неіснуючого рядка, як у розглянутому випадку, то цей варіант відслідкований не буде, що приведе до виводу значень NULL.
Після вибірки останнього рядка буде ще один вибір з курсору, що дасть невдачу (-1), але буде відображений на екрані як заголовок без виведеного рядка.
Для боротьби із цими недоліками цикл був змінений таким чином, що умова продовження роботи циклу стала завжди істинною; вибір з курсору повністю перемістився в цикл і здійснюється в змінні; у випадку невдалого вибору з курсору (@@FETCH_STATUS повертає -1) відбувається вихід із циклу, а якщо вибір рядка з курсору вдалий, то відбувається вивід значень змінних на екран за допомогою команди SELECT.
*/
while (1 = 1)
begin
fetch next from cursor2 into @c1, @c2
set @fetch_res = @@FETCH_STATUS
if (@fetch_res = -1)
break;
if (@fetch_res <> -2)
select @c1 as c1, @c2 as c2
end
/*
Закриваємо курсор.
*/
close cursor2