Widoki i sekwencje Widoki Jeśli często wykonujemy jakiej zapytanie do bazy danych, np. z użyciem wielu tabel lub po prostu długie, możemy zdefiniować widok. Korzystanie z niego będzie o wiele wygodniejsze. Możemy pobierać z niego dane jak ze zwykłej tabeli. Nagle długie zapytanie z wieloma parametrami do którego często trzeba coś dodawać możemy zamienić w mniej więcej coś takiego: SELECT * FROM NAZWA_WIDOKU Widoki są strukturami całkowicie dynamicznymi, tzn. zapytanie, które je definiuje w momencie definicji jest tylko sprawdzane pod względem poprawności składniowej i semantycznej, natomiast nie jest wykonywane. Zapytanie to jest wykonywane w momencie odwoływania się do widoku. Widoki mają też zastosowanie w przypadku nadawania uprawnień. Możemy chcieć udostępnić użytkownikowi tylko część danych, lub część kolumn z tabeli. W takim wypadku tworzymy widok o zadanych właściwościach, a użytkownikowi zezwalamy na dostęp do widoku a nie tabeli. Tworzenie widoków CREATE [OR REPLACE] [FORCE] VIEW NAZWA_WIDOKU AS TREŚĆ_ZAPYTANIA [ WITH READ ONLY] [WITH CHECK OPTION] Aby stworzyć widok, należy mieć uprawnienia do wszystkich obiektów do których odnosi się widok. OR REPLACE - Dzięki tej klauzuli w przypadku gdyby widok o takiej nazwie już istniał zostanie nadpisany przez właśnie tworzony. FORCE - Wymusza stworzenie widoku nawet jeśli zapytanie będące podstawą widoku jest niepoprawne (np. odnosi się do tabeli która jeszcze nie istnieje). WITH READ ONLY - W niektórych przypadkach można stosować instrukcje DML na widokach, ta instrukcja nawet jeśli formalnie byłoby to możliwe, uniemożliwia to. WITH CHECK OPTION - Ta opcja sprawia, że w przypadku (jeśli to możliwe dla danego widoku) nie można wrzucić danych albo zmienić ich w taki sposób że nie będą widoczne w tym widoku. Wykonywanie operacji DML na widokach W przypadku zapytań, widoki funkcjonują tak jak tabele. W zależności od operacji DML widoki dotyczą różne właściwości. W żadnym z poniższych wypadków nie możemy wykonać operacji jeśli widok został stworzony z kauzulą WITH READ ONLY. Update Widok nie może być oparty na wielu tabelach Nie może zawierać klauzuli DISTINCT Nie może zawierać GROUP BY ani funkcji grupowych Nie może zawierać skorelowanych zapytań
Wyrażeń w kolumnie Delete Widok nie może być oparty na wielu tabelach Nie może zawierać klauzuli DISTINCT Nie może zawierać GROUP BY ani funkcji grupowych Nie może zawierać skorelowanych zapytań Insert Widok nie może być oparty na wielu tabelach Nie może zawierać klauzuli DISTINCT Nie może zawierać GROUP BY ani funkcji grupowych Nie może zawierać skorelowanych zapytań Wyrażeń w kolumnie Tabela, na której oparty jest widok zawiera kolumnę NOT NULL bez wartości domyślnej, i kolumna ta nie jest odwzorowana w widoku. Jeżeli widok zostanie utworzony z klauzulą WITH CHECK OPTION, to nie będzie można wstawić do niego żadnego wiersza, który nie byłby później widoczny w tym widoku. Usuwanie widoków DROP VIEW NAZWA_WIDOKU; Synonimy Synonim jest alternatywną nazwą obiektu bazy danych. Synonimy mogą być prywatne (widoczne tylko dla użytkownika który je stworzył) lub publiczne (czyli widoczne dla wszystkich). Tworzenie synonimów Ogólna konstrukcja polecenia zakładania synonimu wygląda tak: CREATE [OR REPLACE] [ PUBLIC ] SYNONYM [ użytkownik ].nazwa_synonimu FOR [ użytkownik ].nazwa_obiektu Stosując OR REPLACE możemy nadpisać synonim o takiej nazwie w przypadku gdyby istniał. Jeśli jeszcze nie będzie takiego synonimu, Oracle go stworzy. Dodając klauzulę PUBLIC umożliwiamy innym użytkownikom dostęp do naszego synonimu (synonim będzie dla nich widoczny, ale aby móc korzystać z obiektu dla którego ten synonim został stworzony, muszą oczywiście mieć do tego obiektu uprawnienia). Dodając nazwę użytkownika przed nazwą synonimu tworzymy synonim w wybranym schemacie. Jeśli pominiemy nazwę użytkownika, Oracle stworzy synonim w naszym schemacie. Przed nazwą obiektu dla którego tworzony jest synonim możemy dodać nazwę użytkownika w którego schemacie znajduje się obiekt do którego odnosi się synonim. Usuwanie synonimów Konstrukcja :
DROP [PUBLIC] SYNONYM UZYTKOWNIK.NAZWA; Klauzulę PUBLIC stosujemy jeśli istnieje synonim publiczny i np. nasz prywatny o takich samych nazwach a chcemy skasować ten publiczny. Informujemy dzięki temu Oracle o który nam chodzi. Słowniki systemowe Oracle udostępnia słownik systemowy zawierający informacje o wszystkich obiektach w bazie danych. Na słownik ten nałożone są widoki które wyświetlają różne informacje w zależności od uprawnień użytkownika który z nich korzysta. Warto o nich pamiętać w sytuacjach, ponieważ niejednokrotnie pojawia się konieczność sprawdzenia do jakich obiektów użytkownik ma uprawnienia, lub których jest właścicielem. Najczęściej używane widoki to: user_tables tabele których użytkownik jest właścicielem user_views widoki których użytkownik jest właścicielem user_constraints konstrainty których użytkownik jest właścicielem all_tables tabele których użytkownik jest właścicielem lub ma jakiekolwiek prawa all_views widoki których użytkownik jest właścicielem lub ma jakiekolwiek prawa all_contraints konstrainty których użytkownik jest właścicielem lub ma jakiekolwiek prawa Sekwencje Tworzenie sekwencji Sekwencja jest obiektem podającym kolejne wartości wg ustalonych kryteriów. Sekwencje stosujemy często w celu tworzenia kluczy głównych tabel. Create sequence moja_sekwencja Minvalue 0 Maxvalue 99999 Start with 0 Increment by 1; Na podstawie wyżej przytoczonego przykładu: create sequence - Po tym następuje podanie nazwy sekwencji. W nazwie sekwencji nie może być spacji. Minvalue - Wartość minimalna jaką może przybrać sekwencja. Maxvalue - Wartość maksymalna jaką może przybrać sekwencja. Start with - Określa wartość od jakiej ma się rozpoczynać sekwencja. Increment by - Określa wartość o jaką ma się zmieniać aktualny stan sekwencji po każdym pobraniu danych. Jako parametr tego polecenia możemy również podać liczbę ujemną. Wartość sekwencji będzie wtedy maleć. Rzadziej używanymi opcjami sekwencji są cycle oraz cache. Cycle / nocycle - Parametr ten określa czy sekwencja może się przekręcić (jak licznik w samochodzie, nie jak teściowa) i rozpocząć naliczanie od początku.
Cache / nocache - klauzula CACHE włącza wykonywanie pre-alokacji numerów sekwencji i przechowywanie ich w pamięci, co skutkuje zwiększeniem szybkości generacji kolejnych liczb. Klauzula NOCACHE wyłącza tę możliwość. Domyślnie przyjmowane jest CACHE 20. Wartość podana w CACHE musi być mniejsza niż MAXVALUE - MINVALUE Order / noorder - Klauzula ORDER gwarantuje, że kolejne liczby będą generowane w porządku jakim otrzymane zostały przez system polecenia ich generacji. Klauzula NOORDER wyłączą tę własność. Pobieranie wartości z sekwencji Do pobierania danych z sekwencji, wykorzystywane są dwie pseudokolumny currval i nextval. Nextval - Służy do pobierania następnej wartości z sekwencji. Currval - Służy do pobierania aktualnej wartości sekwencji. Przed wykorzystaniem currval należy wykonać przynajmniej raz nextval na danej sekwencji. W przypadku braku takiej inicjacji, zarówno currval jak i nextval będą miały tą samą wartość odpowiadającą parametrowi start with dla danej sekwencji. Pobierać wartości z sekwencji możemy na dwa sposoby. Wykorzystywać do tego select na tabeli (np. dual) lub w instrukcjach DML. Select moje_sekwencja.nextval from dual; Select moje_sekwencja.currval from dual; Wykorzystanie sekwencji w instrukcjach DML Dodając dane do tabeli często zachodzi konieczność wygenerowania dla każdego wpisu unikalnego id dla każdego wiersza. Zdarza się że jest to wymagane z powodu założenia na danej tabeli klucza głównego. W takiej sytuacji najwygodniej jest skorzystać z sekwencji. Sekwencje mogą produkować tylko wartości liczbowe. Insert into jobs values(moja_sekwencja.nextval, test, 1000, 2000); Usuwanie sekwencji Aby usunąć stworzoną sekwencję należy wykorzystać polecenie drop o następującej kontrukcji: DROP sequence nazwa sekwencji; Modyfikacja sekwencji Aby zmienić lub nadać jakiś parametr istniejącej sekwencji stosujemy konstrukcję: ALTER SEQUENCE NAZWA_SEKWENCJI NAZWA PARAMETRU {WARTOŚĆ}; Nie możemy tylko zmienić parametru START WITH. Indeksy i transakcje Indeksy Indeksy pozwalają zdecydowanie przyspieszyć wyszukiwanie wierszy w tabelach. W przypadku braku indeksu znalezienie wiersza spełniającego pewien warunek wymagałoby przejrzenia wiersz po
wierszu całej tabeli. W przypadku dużych i bardzo dużych tabel, takie wyszukiwanie mogłoby trwać bardzo długo. W związku z drzewiastą konstrukcją indeksu można szybko znaleźć położenie poszukiwanych wierszy. Sprawia to że wyszukiwanie trwa zawsze krótko. Tworzenie indeksu Ogólna konstrukcja polecenia tworzącego indeks: CREATE INDEX NAZWA_INDEKSU ON NAZWA_TABELI (KOLUMNA,KOLUMNA2); Indeksy możemy zakładać na więcej niż jednej kolumnie. Wystarczy dodać je po przecinku. Indeksy warto zakładać na tych kolumnach które często występują w zapytaniach jako warunek w filtracji wierszy. Wraz z zmianą zawartości tabeli spada wydajność stworzonych indeksów. Dlatego należy co jakiś czas odtwarzać indeksy od nowa. Usuwanie indeksu DROP INDEX NAZWA_INDEKSU Transakcje Zarządzanie transakcjami Transakcja jest zbiorem operacji wykonywanych w ramach jednej sesji. Wszystkie operacje na bazie danych realizowane są w postaci ciągu transakcji. Transakcyjność zapewnia nam bezpieczeństwo i stabilną pracę bazy danych. Wszystkie instrukcje w ramach jednej transakcji zostają wykonane w całości lub w całości zostają wycofane. Dzięki temu nie powstaje sytuacja, w której tylko część danych modyfikowanych w przerwanej transakcji zostaje zmieniona. Dane które podlegają zmianie, są odizolowane od innych użytkowników i procesów pracujących na bazie danych do czasu zakończenia transakcji. Instrukcja COMMIT Transakcja jest zatwierdzana i kończy się w chwili wykonania instrukcji COMMIT. Wszystkie modyfikacje danych zostają zapisane w bazie. W przypadku wykonania którejkolwiek z instrukcji należącej do grupy DML wykonywany jest niejawny COMMIT. Należy również zwrócić uwagę na ustawienia naszych edytorów SQL. Często jest w nich ustawiony domyślnie autocommit. Transakcje w takim wypadku zatwierdzane są bez wykonania przez nas instrukcji COMMIT. Instrukcja ROLLBACK Instrukcja ROLLBACK wycofuje wszystkie modyfikacje danych w ramach jednej transakcji. Możemy ją zastosować jeśli się np. pomylimy. Ta instrukcja nie zadziała jeśli wykonamy COMMIT. Transakcja w takim wypadku jest już zakończona. Instrukcja SAVEPOINT Instrucja SAVEPOINT pozwala zachowywać punkty przywracania działa to tak jak zapisywanie stanu w czasie gry :) W przypadku pomyłki możemy wrócić do miejsca zapisania SAVEPOINT bez straty tych instrukcji które zostały wykonane przed nim i konieczności rozpoczynania gry od początku.
Aby założyć nowy savepoint stosujemy: SAVEPOINT NAZWA_SAVEPOINTA; Aby przywrócić stan do określonego savepointa stosujemy: ROLLBACK TO NAZWA_SAVEPOINTA; Blokowanie tabel Blokada pozwala zachować spójność danych w przypadku modyfikacji tych samych danych przez wiele transakcji. Tabele mogą być blokowane przez serwer Oracle lub przez nas samych. Blokada automatycznie zakładana jest na te wiersze w tabeli które są aktualnie modyfikowane. Blokowanie wierszy przez użytkownika Zdarzają się sytuacje, dotyczy to zwłaszcza danych krytycznych, że chcemy mieć pewność że przez pewien czas kiedy realizujemy jakieś update na tabeli nic nie zostanie w niej zmienione przez innych użytkowników. Generalnie dążymy do tego by blokować jak najmniej danych, a jednocześnie nikt nam nie namieszał. W takiej sytuacji możemy zablokować tylko te dane które chcemy zmieniać. Jeśli przykładowo chcemy updatować dane w taki sposób: UPDATE JOBS SET MIN_SALARY=3000 WHERE JOB_TITLE LIKE '%Manager%'; możemy zablokować te wiersze przy pomocy nieco zmodyfikowanego selecta który wyciągnie nam dane do modyfikacji: SELECT MIN_SALARY FROM JOBS WHERE JOB_TITLE LIKE '%Manager%' for update; Dodanie klauzuli for update sprawi że wiersze te zostaną zablokowane dla innych użytkowników do czasu, aż nie zatwierdzimy transakcji (COMMIT), lub jej nie wycofamy (ROLLBACK). Po klauzuli for update można wymienić tylko te kolumny które będziemy updatować. W przypadku blokady na jednej tabeli i tak zostaną zablokowane całe wiersze. Jeśli po FOR UPDATE wymienimy kolumny, ale zapytanie oparte jest o więcej niż jedną tabelę, zablokowane zostaną wiersze tylko w tej tabeli której kolumny wymienimy po FOR UPDATE. SELECT MIN_SALARY FROM JOBS WHERE JOB_TITLE LIKE '%Manager%' for update MIN_SALARY; W czasie trwania blokady inny użytkownik po wprowadzeniu instrukcji DML uzyska taki efekt, że jego sesja zostanie niejako zawieszona. Zapytanie będzie oczekiwało na wykonanie do momentu kiedy przez użytkownika blokującego dane nie zostaną odblokowane. Blokada nie dotyczy poleceń odczytu danych. Blokowanie tabel przez użytkownika (LOCK TABLE) Możemy również zablokować dostęp do całej tabeli, a nie tylko pojedynczych wierszy. Ogólna konstrukcja polecenia blokady wygląda tak: LOCK TABLE NAZWA_TABELI IN NAZWA_TRYBU MODE;
SHARE LOCK TABLE JOBS IN SHARE MODE; - Jest to blokada która umożliwia zakładanie innych blokad z wyjątkiem blokady EXCLUSIVE. Stosuje się ją najczęściej przy operacjach nie ingerujących w konstrukcję tabeli, układ zależności tabel. Inne blokady, w tym blokady zakładane automatycznie w poleceniach DML będą oczekiwały na zwolnienie blokady. EXCLUSIVE LOCK TABLE JOBS IN EXCLUSIVE MODE; - Ta blokada uniemożliwia założenie jakichkolwiek innych blokad, w tym blokad zakładanych automatycznie przy poleceniach DML. Stosuje się ją najczęściej gdy ingerujemy w konstrukcję tabeli lub układ zależności tabel np. przy stosowaniu poleceń ALTER, DROP, zakładaniu constraintów. NOWAIT Jeśli zastosujemy klauzulę NOWAIT : LOCK TABLE JOBS IN SHARE MODE NOWAIT; - nie będziemy oczekiwali zawieszeni na zwolnienie blokady, a otrzymamy informację, że w tej chwili założenie blokady nie jest możliwe. Zadania Widoki do bazy HR 1. Stwórz widok który umożliwi wyświetlanie pracowników z departamentu o podanej nazwie. 2. Stwórz widok który umożliwi dodawanie nowego wiersza do tabeli regions 3. Przez widok zdubluj dane zawarte w tabeli regions. Widoki do bazy ewidencji pracowników uczelni 4. Stwórz widok który wyświetla: a. wszystkich przełożonych i nazwy zespołów, w których pracują, b. listę etatów (bez duplikatów) na których zatrudnieni są pracownicy uczelni, c. wszystkie dane o pracownikach zespołów 30 i 40 w kolejności malejących zarobków, d. nazwiska, daty zatrudnienia i etaty asystentów zatrudnionych w 1992 lub 1993 roku, e. nazwiska i płace pracowników powiększone o 15% i zaokrąglone do liczb całkowitych, f. wyświetlającą dla każdego szefa jego podwładnych, g. wyświetlającą jaki mamy dziś dzień tygodnia. Sekwencje do bazy ewidencji pracowników uczelni 5. Stwórz sekwencję która rozpoczyna się od 1, o wartości maksymalnej 9999 postępującą o 1. 6. Stwórz sekwencję która rozpoczyna się od 9999, o wartości minimalnej 1 postępującą o 4. 7. Sprawdź wartość sekwencji nie zmieniając jej wartości. 8. Wpisać 3 wiersze do tabeli prac, wykorzystując licznik do generowania unikalnych numerów pracowników. Licznik ma być acykliczny, ma rozpocząć zliczanie od wartości 543 i zwiększać się o 5 po każdym odczycie nowej wartości. 9. Utwórz sekwencję MYSEQ rozpoczynającą się od 300 i zwiększającą się w każdym kroku o 10. 10. Wykorzystaj utworzoną sekwencję do wstawienia nowego stażysty o nazwisku Pabacki do relacji Pracownicy. 11. Zmodyfikuj pracownikowi Pabackiemu płacę dodatkową na wartość wskazywaną przez sekwencję.
12. Usuń pracownika o nazwisku Pabacki. 13. Stwórz nową sekwencję o niskiej wartości maksymalnej. Zaobserwuj, co się dzieje, gdy następuje przepełnienie sekwencji. Indeksy do bazy HR 14. Stwórz tabelę Miasta : a. zawierającą: id, nazwę miasta, klucz obcy do tabeli regions. b. Załóż klucz główny na pole id tabeli Miasta. c. Załóż klucz unikalny na pole z nazwą miasta. d. Dodaj do tabeli Miasta pole dzielnica e. Załóż indeks na pole dzielnica 7 zad 3 8-9 zad 3,5 10-11 zad 4 12-13 zad 4,5 14 zad 5