Kursory 1
Kursory Kursor jest mechanizmem pozwalającym obsłużyć zbiór zawierający wiele wierszy danych (generowany np. poleceniem SELECT). Jak wskaźnik przebiega on po kolejnych krotkach ze zbioru danych, pozwalając wykonywać operacje na tych krotkach. Najczęstszą operacją jest pobranie aktualnie wskazywanej krotki poleceniem FETCH. 2
DECLARE CURSOR 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 ] ] ] 3
DECLARE CURSOR c.d. gdzie: LOCAL oznacza, że do kursora będzie można odwołać się wyłącznie z bieżącej procedury wsadowej, procedury składowanej lub wyzwalacza, GLOBAL oznacza zakres kursora jako równy sesji użytkownika, FORWARD_ONLY określa, że kursor będzie mógł być przesuwany jedynie od pierwszego do ostatniego rekordu. Jedynym sposobem pobrania danych poprzez tak zadeklarowany kursor jest wykonanie polecenia FETCH NEXT, SCROLL umożliwia odwoływanie się do dowolnych rekordów zwróconych przez kursor, STATIC powoduje utworzenie tymczasowej tabeli (w bazie tempdb) przechowującej rekordy kursora. Zmiany w tabeli źródłowej, które nastąpiły po jego zadeklarowaniu nie będą widoczne poprzez kursor, KEYSET powoduje utworzenie tymczasowej tabeli keyset (w bazie tempdb) przechowującej identyfikatory tabeli źródłowej kursora. Aktualizacje rekordów, których identyfikatory zostały zapisane w tabeli keyset, będą widoczne poprzez kursor, natomiast dodanie nowych wierszy do tabeli źródłowej nie, DYNAMIC powoduje, że wszystkie zmiany w tabeli źródłowej będą widoczne poprzez kursor, FAST_FORWARD powoduje utworzenie kursora typu FORWARD_ONLY umożliwiającego jedynie odczytywanie danych i zoptymalizowanego pod kątem odczytywania kolejnych rekordów. 4
Przykład: deklaracja kursora o nazwie kursorek i związanie go z wynikiem polecenia SELECT otwarcie kursora pobranie pierwszego wiersza ze zbioru zwróconego przez SELECT i podstawienie jego wartości (nazwisko) pod zmienną pobieranie w pętli kolejnych wierszy aż do ostatniego DECLARE @nazw VARCHAR(20) DECLARE kursorek CURSOR FOR SELECT nazwisko FROM pracownicy OPEN kursorek FETCH NEXT FROM kursorek INTO @nazw WHILE @@FETCH_STATUS = 0 BEGIN PRINT @nazw FETCH NEXT FROM kursorek INTO @nazw END zamknięcie kursora i dealokacja pamięci CLOSE kursorek DEALLOCATE kursorek 5
@@FETCH_STATUS - zwraca status (wartość INTEGER) ostatnio wykonanego polecenia FETCH któregokolwiek z aktualnie otwartych kursorów. Znaczenie: 0 polecenie FETCH zakończyło się pomyślnie -1 polecenie FETCH nie powiodło się lub kursor znalazł się poza zbiorem wynikowym -2 pobrany wiersz został utracony 6
Zadanie Za pomocą kursorów utwórz następujący raport: dla każdego działu podaj jego nazwę i liczbę pracowników oraz procentowy udział każdego stanowiska w ogólnej liczbie pracowników tego działu. Raport ma mieć następującą postać: ADMINISTRACJA 3 pracowników -------------------------------------- - ADIUNKT 0% - ASYSTENT 33.33% - DYREKTOR 33.33% - PROFESOR 0% - SEKRETARKA 33.33% - STAZYSTA 0% SYSTEMY ROZPROSZONE 7 pracowników -------------------------------------- - ADIUNKT 28.57% - ASYSTENT 42.86%... 7
Zadanie Dana jest tabela TABELA(nazwa) o czterech krotkach: a, b, c, d. Jaki będzie wynik działania poleceń i dlaczego: A DECLARE @nazwa VARCHAR(20) DECLARE kursorek CURSOR FOR SELECT nazwa FROM tabela OPEN kursorek FETCH NEXT FROM kursorek INTO @nazwa DELETE FROM tabela WHERE nazwa='c' WHILE @@FETCH_STATUS = 0 BEGIN PRINT @nazwa FETCH NEXT FROM kursorek INTO @nazwa END CLOSE kursorek DEALLOCATE kursorek B DECLARE @nazwa VARCHAR(20) DECLARE kursorek CURSOR STATIC FOR SELECT nazwa FROM tabela OPEN kursorek FETCH NEXT FROM kursorek INTO @nazwa DELETE FROM tabela WHERE nazwa='c' WHILE @@FETCH_STATUS = 0 BEGIN PRINT @nazwa FETCH NEXT FROM kursorek INTO @nazwa END CLOSE kursorek DEALLOCATE kursorek 8