Rodzaje baz danych – podział ze względu na model danych

Istnieje wiele różnych rodzajów baz danych i klasyfikacji ich podziału, jednakże najistotniejszym wydaje się rozróżnienie ze względu na model danych. Poniżej zostały opisane najważniejsze z nich [Beynon-Davies 2003].

Relacyjny model danych
Niezwykłość relacyjnego modelu danych polega na tym, że swoje powstanie zawdzięcza głównie jednej osobie – E.F. Coddowi. W 1970 r. Codd opublikował fundamenty dla najbardziej popularnego ze współczesnych modeli danych. Od 1968 do 1988 r. Codd opublikował ponad 40 prac na temat relacyjnego modelu danych. Codd traktuje swoje prace wydane przed 1979 r. jako pierwszą wersję relacyjnego modelu danych [Codd, 1990]. Na początku 1979 r. na konferencji Australian Computer Society Codd przedstawił pracę pod tytułem Extending the Relational Database Model to Capture More Meaning. Rozszerzoną wersję relacyjnego modelu danych, którą sformułował w jednej z swojej prac, Codd nazwał RM/T (T od Tasmania). Na początku 1990 r. Codd opublikował książkę pod tytułem The Relational Model for Database Management: Version 2. Jednym z powodów opublikowania książki, na który zwraca uwagę Codd, jest fakt, iż uważa on, ze wielu producentów produktów bazodanowych powołujących się na relacyjny model danych nie rozumie implikacji zawartych nie tylko w modelu RM/T, ale również w pierwszej wersji relacyjnego modelu danych [Beynon-Davies 2003].
Relacyjny model zakłada, iż jest potrzebna tylko jedna struktura danych – relacja.
W związku z tym, że pojęcie relacji jest matematyczną konstrukcją, relacja jest tabelą, dla której jest spełniony następujący zbiór zasad
1. Każda relacja w bazie danych ma jednoznaczną nazwę.
2. Każda kolumna w relacji ma jednoznaczną nazwę w ramach jednej relacji.
3. Wszystkie wartości w kolumnie muszą być tego samego typu. Mówimy, że są one zdefiniowane na tej samej dziedzinie.
4. Porządek kolumn w relacji nie jest istotny.
5. Każdy wiersz w relacji musi być różny. Innymi słowy, powtórzenia wierszy nie są dozwolone w relacji.
6. Porządek wierszy nie jest istotny.
7. Każde pole leżące na przecięciu kolumna/wiersz w relacji powinno zawierać wartość atomową. To znaczy, że zbiór wartości nie jest dozwolony na jednym polu relacji.

Każda relacja musi mieć klucz główny. Dzięki temu możemy zapewnić, niepowtarzalność wierszy w relacji. Klucz główny to jedna lub więcej kolumn tabeli, w której wartości jednoznacznie identyfikują każdy wiersz w tabeli [Beynon-Davies 2003].
W każdej relacji może istnieć wiele kluczy kandydujących, czyli kolumna lub zbiór kolumn, które mogą występować jako jednoznaczny identyfikator wierszy w tabeli. Klucz główny jest wybierany ze zbioru kluczy kandydujących [Beynon-Davies 2003].
Każdy klucz kandydujący, a więc także klucz główny, musi mieć dwie właściwości.
Po pierwsze być jednoznaczny i nie może mieć wartości „null” – specjalnego znaku wskazującego na brakujące lub niepełne dane. Następnie, z definicji każdy klucz kandydujący musi być jednoznacznym identyfikatorem. Stąd też, nie może być żadnych powtarzających się układów wartości w kolumnach kluczy kandydującego lub głównego. Po wtóre, wartość klucza głównego musi być określona dla każdego wiersza w tabeli. Innymi słowy,
w kolumnie lub kolumnach klucza głównego nie może wystąpić wartość „null” (oznaczająca brak wartości) [Beynon-Davies 2003].
Podstawową jednostką danych w relacyjnym modelu danych jest element, na przykład numer pracownika (244), nazwisko wykładowcy (S. Kowalski) lub data urodzenia studenta (1/7/1984). Mówimy, że takie elementy są nierozkładalne lub atomowe. Zbiór takich elementów danych tego samego typu nazywamy dziedziną. Na przykład dziedziną numerów pracowników jest zbiór wszystkich możliwości numerów pracowników. Dziedzinami są więc zbiory wartości, z których pochodzą elementy pojawiające się w kolumnach tabeli
[Beynon-Davies 2003].
Klucze obce łączą dane przechowywane w różnych tabelach. Klucz obcy jest kolumną lub grupą kolumn z jednej tabeli, która czerpie swoje wartości z tej samej dziedziny co klucz główny tabeli powiązanej z nią w bazie danych. W systemach relacyjnych wprowadzamy specjalną wartość, aby wskazać niepełną lub nieznaną informację – wartość „null”.
Ta wartość, różna od zera i spacji, jest szczególnie użyteczna przy powiązaniu kluczy głównego i obcego [Beynon-Davies 2003].
Pojęcie wartości null nie jest jednak do końca akceptowalne. Codd utrzymuje, że wprowadzenie wartości null do systemu relacyjnego zmienia logikę dwuwartościową (prawda, fałsz) na trójwartościową (prawda, fałsz, nieznane). W logice dwuwartościowej, jeżeli zdanie jeden jest prawdziwe i zdanie dwa jest prawdziwe, to ich połączenie spójnikiem „i” jest również prawdziwe. W logice trójwartościowej, jeżeli zdanie 1 jest prawdziwe,
a zdanie 2 ma wartość nieznaną, to ich połączenie spójnikiem „i” ma wartość nieznaną. Wprowadza to dodatkowe komplikacje przy przetwarzaniu zapytań. Niektórzy komentatorzy (np. Chris Date) twierdzą, że jest to zbędne [Beynon-Davies 2003]. Moim zdaniem dobrze zaprojektowana baza danych minimalizuje wystąpienia wartości nieokreślonej lub nawet ją wyklucza. Ewentualnie obsługa null jest przemyślana w sposób całkowicie zgodny
z implementacją dostawcy systemu bazodanowego obsługującego projektowaną bazę co
z kolei sprowadza się do wyboru dostawcy na wczesnym etapie projektowania bazy.
W przeciwnym wypadku baza jest narażona na utratę spójności właśnie przez następstwa logiki trójwartościowej. Może dojść także do sytuacji iż mimo spójności danych w bazie wyniki zapytań do bazy będą niespójne.
Kiedy Codd na początku zaproponował relacyjny model danych, najwięcej uwagi poświęcał wyszukiwaniu danych, które jest wykonywane przy pomocy operatorów znanych jako algebra relacyjna [Beynon-Davies 2003].
Algebra relacyjna jest zbiorem ośmiu operatorów. Każdy operator bierze jedną lub więcej relacji jako argument i produkuje jedną relację jako wynik. Trzema głównymi operatorami algebry relacyjnej są: restrykcja, rzut i złączenie. Dzięki tym trzem operatorom możemy wykonać większość operacji na danych wymaganych od systemu relacyjnego.
Dodatkowe operatory – iloczyn, suma, przecięcie, różnica i iloraz – opierają się na tradycyjnych operatorach teorii zbiorów. W relacyjnym modelu danych istnieją dwa rodzaje wewnętrznych reguł integralności: integralność encji i integralność referencyjna. Są one wewnętrzne, ponieważ każda relacyjna baza danych musi wykazywać oba aspekty integralności [Beynon-Davies 2003].
Integralność encji dotyczy kluczy głównych. Jest ona również regułą integralności, która mówi, że każda tabela musi mieć klucz główny oraz że kolumna lub kolumny wybrane jako klucz główny powinny być jednoznaczne i nie zawierać wartości null. Bezpośrednią konsekwencją reguły integralności encji jest fakt, że w tabeli są zabronione powtórzenia wierszy. Jeżeli każda wartość klucza głównego musi być różna, to w tabeli nie może się pojawić żaden powtarzający się wiersz. Integralność encji jest definiowana przez dodanie do definicji schematu klauzuli klucza głównego [Beynon-Davies 2003].
Integralność referencyjna dotyczy kluczy obcych. Reguła integralności referencyjnej mówi, że każda wartość klucza obcego może się znajdować tylko w jednym z dwóch stanów. Normalnie wartość klucza obcego odwołuje się do wartości klucza głównego w tabeli w bazie danych. Czasami wartość klucza obcego może być null i fakt ten zależy od zasad związanych z przedsięwzięciem. W tym wypadku jawnie stwierdzamy, że nie ma związku
z reprezentowanymi obiektami w bazie danych albo że ten związek jest nieznany
[Beynon-Davies 2003]. Jednakże dzisiejesze implementacje modeli relacyjnych jawnie dopuszczają sytuację, w której wartość klucza będzie spoza zbioru wartości klucza głównego. Jest to sytuacja niebezpieczna i moim zdaniem powinna być eliminowana. Wyobraźmy sobie sytuację, w której definiujemy informacje np. o studentach. Wówczas kluczem obcym
w tabeli studentów niech będzie informacja z identyfikatorem miasta, z którego pochodzi student. W sytuacji gdy projektant bazy zezwoli na wykroczenie klucza obcego ze zbioru klucza głównego np. poprzez usunięcie danej miejscowości z bazy, otrzymamy bazę w stanie niespójnym, mało tego zezwolimy aby ta niespójność została usunięta i wprowadzi ona bazę w stan, w którym jawnie i w świetle prawa baza zwróci informację fałszywą jako prawdziwą. Wystarczy tylko wprowadzić inne miasto, które otrzyma taki sam identyfikator jak to usunięte. W ten o to sposób student urodzony w Krakowie w naszej bazie mógł zmienić miejsce swoich narodzin. Niespójność taka jest bardzo trudna do wykrycia i może powodować kaskodową eskalację problemu. Problemem w takiej sytuacji jest także przywrócenie systemu do stanu poprawnego. W momencie gdy zostanie wprowadzone nowe miasto np. Poznań i otrzyma ono identyfikator Krakowa, po dodaniu nowych studentów urodzonych w Poznaniu powstanie problem odróżnienia ich od tych, którzy zostali urodzeni w Krakowie.
Utrzymanie integralności referencyjnej nie ogranicza się do określenia, czy klucz obcy może mieć wartość null, czy nie. Obejmuje ono również określenie więzów propagacji, które określają, co powinno się stać z powiązaną tabelą, gdy modyfikujemy wiersz lub wiersze
w docelowej tabeli [Beynon-Davies 2003].
Dla każdego związku między tabelami w naszej bazie danych powinniśmy określić, jak mamy postępować z usuwaniem docelowych i powiązanych kartotek. Na przykład, jeżeli usuniemy wiersz z tabeli w bazie danych, to musimy zdecydować, co powinno się stać
z powiązanymi wierszami w tabeli korzystającej z klucza obcego wskazującego na tabele,
w której usuwamy wiersz.
Są trzy (a właściwie cztery) możliwości:
1. Ograniczone usuwanie (ang. restricted delete). Jest to ostrożne podejście. Oznacza to, że zabraniamy usunąć wiersz np. z danymi wykładowcy dopóty, dopóki nie będą usunięte wszystkie wiersze informacji o zajęciach prowadzonych przez tego wykładowcę.
2. Kaskadowe usuwanie (ang. cascades delete). Jest to ufne podejście. Jeżeli usuwamy wiersz np. nagłówka dokumentu, to są jednocześnie usuwane wszystkie powiązane
z nim pozycje tego dokumentu.
3. Wstaw null przy usuwaniu (ang. nullifies delete). Jest to wyważone podejście. Jeżeli usuwamy wiersz wykładowcy, to numery pracowników w powiązanych wierszach przedmiotów ustawiamy na null [Beynon-Davies 2003].
4. Istnieje także możliwość wymuszenia braku akcji (ang. no action). Jest to podejście wysoce nie rozważne, co uargumentowałem we wstępie do integralności referencyjnej. Jeżeli usuniemy wiersz klucza głównego (wykładowcy) to wartości klucza obcego
(np. prowadzonych przez niego przedmiotów nie ulegną zmianie).

Za pomocą wewnętrznej integralności nie możemy wyrazić wszystkich aspektów integralności należących do konkretnej aplikacji. Oznacza to, że są wymagane inne mechanizmy, aby wyrazić inne postacie integralności Do schematu relacji możemy dodać aspekty dodatkowej integralności przez dołączenie ciągu definicji więzów. Takie definicje mogą być zapisane w postaci wyrażeń algebry relacyjnej lub rachunku relacyjnego. Na przykład, chociaż możemy zapewnić, aby każdy wykładany przedmiot miał przypisanego do niego wykładowcę (przez umieszczenie przy kluczu obcym identyfikatora wykładowcy klauzuli not null), nie możemy za pomocą więzów wewnętrznych wyrazić faktu, że każdy wykładowca ma obowiązek prowadzenia przynajmniej jednego przedmiotu
[Beynon-Davies 2003].

Hierarchiczny model danych
Hierarchiczny model danych nie ma takiej samej jednolitości oraz teoretycznej podstawy jak model relacyjny. Można powiedzieć, że ten model danych został opracowany
w wyniku analizy istniejącej implementacji. Prawdopodobnie najbardziej wyróżniającym się DBMS, odpowiadającym hierarchicznemu podejściu, jest IMS (ang. Information Management System) firmy IBM [Beynon-Davies 2003].
Hierarchiczny model danych używa dwóch struktur, którymi są: typy rekordów
i związek a właściwie relacja nadrzędny-podrzędny. Typ rekordu jest określoną strukturą danych, złożoną ze zbiorów nazwanych pól, np. ID_Student i Nazwisko_Studenta. Każde pole jest używane do przechowywania prostego atrybutu i jest mu przyporządkowany typ danych. Powiązanie nadrzędny-podrzędny jest związkiem jeden do wielu między dwoma typami rekordów. Typ rekordu po stronie ‘jeden’ związku jest nadrzędnym typem rekordu, takim jak kierunek studiów; rekord po stronie ‘wiele’ jest podrzędnym typem rekordu, takim jak przedmiot. Schemat hierarchiczny jest złożony z wielu typów rekordów, powiązanych ze sobą za pomocą związków nadrzędny-podrzędny [Beynon-Davies 2003].
Istnieje wiele wewnętrznych więzów integralności w modelu hierarchicznym, które są obecne zawsze, gdy tworzony jest schemat hierarchiczny. Najważniejsze z nich to:
1. Nie mogą istnieć żadne wystąpienia rekordów, z wyjątkiem rekordu korzenia (najwyższego w hierarchii), bez powiązania z odpowiednim wystąpieniem rekordu nadrzędnego. Dlatego też nie można wstawić rekordu podrzędnego dopóty, dopóki nie zostanie powiązany
z rekordem nadrzędnym, oraz że usunięcie rekordu nadrzędnego powoduje automatyczne usunięcie wszystkich powiązanych z nim rekordów podrzędnych.
2. Jeżeli podrzędny typ rekordu ma związane dwa lub więcej nadrzędnych typów rekordów, to rekord podrzędy musi zostać powielony dla każdego rekordu podrzędnego
[Beynon-Davies 2003].
Sieciowy model danych
Pod względem hierarchicznym sieciowy model danych jest używany przez wiele osób za następcę hierarchicznego modelu danych. W latach siedemdziesiątych większość komercyjnych DBMS przeszła, aczkolwiek bez zachowania pełnej zgodności, na sieciowy model danych. Ostatnim istotnym zdarzeniem dotyczącym sieciowego modelu danych było zarekomendowanie w 1986 r. przez organizację ANSI języka definicji sieciowych
(ang. Network Definition Language; NDL) [Beynon-Davies 2003].
Integralność w modelu sieciowym dotyczy głównie określenia członkostwa w kolekcji i trybu wstawiania. Członkostwo w kolekcji musi być oznaczone, jako wymagane lub opcjonalne. Jeśli status jest ustawiony na wymagane, to system spowoduje, że każde wystąpienie rekordu członka będzie wystąpieniem danej kolekcji. Dla członków kolekcji jest predefiniowany tryb wstawiania. Jeśli tryb wstawiania jest ustawiony na ręczny, to programy użytkowe muszą wstawiać rekordy członków do określonego wcześniej wystąpienia konkretnej kolekcji. Jeśli tryb wstawiania jest automatyczny, to, gdy jest tworzony rekord członka, jest on automatycznie wstawiany do bieżącego wystąpienia danej kolekcji
[Beynon-Davies 2003].

Baza danych – definicja, informacje teoretyczne

Baza danych jest pewnym modelem wycinka rzeczywistości w danej organizacji
(np. firmie, uczelni). Tę rzeczywistość nazywamy obszarem analizy (ang. Uniwerse Of Discourse, UOD) [Beynon-Davies 2003].
Bazę danych możemy uważać za zbiór danych (faktów), których zadaniem jest reprezentowanie określonego UOD. Jednostka danych, jest symbolem, którego używamy, aby reprezentować jakąś rzecz. Chcąc by fakty były użyteczne, muszą być one zinterpretowane. Dane zinterpretowane to informacje. Natomiast informacje to dane w otoczeniu (kontekście) nadającym im znaczenie. Zbiór faktów lub predykatów na temat obszaru analizy tworzą bazę danych. Zazwyczaj fakty negatywne, np. które przedmioty nie są zaliczane przez studenta, nie są przechowywane [Beynon-Davies 2003].
W ściśle określonej chwili baza danych znajduje się w pewnym stanie. Stan oznacza zbiór faktów, które są prawdziwe w danej chwili. Dlatego też bazę danych uważamy za bazę faktów, która zmienia się w czasie [Beynon-Davies 2003].
Baza danych składa się z części intensjonalnej oraz ekstensjonalnej. Część intensjonalna bazy danych jest zbiorem definicji, które opisują strukturę danych. Z kolei część ekstensjonalna jest łącznym zbiorem danych w bazie danych. Intensjonalną stronę bazy danych nazywamy schematem bazy danych. Tworzenie schematu systemu bazy danych jest
w istocie procesem projektowania bazy danych. Baza danych musi być zaprojektowana. Natomiast proces projektowania bazy danych jest czynnością polegającą na reprezentowaniu klas, atrybutów i związków w bazie danych [Beynon-Davies 2003].

Charakterystyka baz danych

Dane w bazie danych traktowane są, jako trwałe. Przez trwałość rozumiemy, że dane są przechowywane przez pewien przedział czasowy. Ten przedział nie musi być bardzo duży. Termin „trwałość” jest używany do rozróżnienia bardziej trwałych danych od informacji, które są tymczasowe. Dlatego dane dotyczące pacjentów, pracowników czy studentów są zwykle uważane za przykłady danych trwałych. Dane wprowadzone przy terminalu, przeznaczone do przetwarzania w programie lub drukowane w postaci raportu, nie są uznane za trwałe, ponieważ po jednym użyciu nie są już dłużej potrzebne [Beynon-Davies 2003].
Chcąc uznać, iż baza danych ma właściwość integralności, musi zawierać dokładne odbicie obszaru analizy. Proces zapewnienia integralności jest jednym z podstawowych zadań systemu zarządzania danymi. Integralność oznacza zapewnienie, że baza danych daje poprawne odpowiedzi na zadane pytania. Jest ważną sprawą, ponieważ większość baz danych jest projektowana z myślą o zmianach zachodzących w trakcie ich używania. Innymi słowy, dane w bazie danych ulegają zmianie w czasie [Beynon-Davies 2003].
W zbiorze możliwych, przyszłych stanów bazy danych niektóre są poprawne,
a niektóre nie. Każdy poprawny stan stanowi zawartość bazy danych w konkretnym momencie. Integralność jest procesem zapewniającym, że baza danych zmienia się
w przestrzeni, określonej przez stany poprawne. Integralność jest związana z określeniem, czy przejście do kolejnego stanu jest poprawne [Beynon-Davies 2003].
Integralność bazy danych jest zapewniana przez więzy integralności, czyli reguły, które określają, w jaki sposób baza danych ma pozostać dokładnym odbiciem swojego obszaru analizy. Więzy (integralności) dzielimy na dwa główne typy: więzy statyczne i więzy przejść.
Więzy statyczne, czyli „niezmiennik stanu”, używamy do sprawdzania, czy wykonywana transakcja nie zmienia stanu bazy danych w stan niepoprawny. Więzy statyczne to ograniczenie określone na stanie bazy danych. Zapewniają np. unikalność wartości bądź zawieranie wartości w określonym zbiorze [Beynon-Davies 2003].
Więzy przejść są to reguły, które wiążą ze sobą stany bazy danych. Przejście jest zmianą stanu i dlatego może być reprezentowane przez parę stanów. Także są ograniczeniem nałożonym na przejście poprzez zablokowanie możliwości zakończenia transakcji przy próbie wprowadzenia faktów niezgodnych z modelem [Beynon-Davies 2003].
Bazy danych są projektowane tak, aby zminimalizować powtarzanie się danych.
W bazie danych chcemy przechowywać tylko jeden element danych na temat obiektów lub związków między obiektami z naszego obszaru analizy. Idealna baza danych powinna być zbiorem niepowtarzających się faktów. Niestety ze względu na zmiany zachodzące w czasie, w celu zachowania integralności danych (zgodności z obszarem analizy) niektóre informacje muszą zostać zapisane więcej niż jeden raz. Przykładem takiego powielania informacji
w bazie jest nagłówek dokumentu. Należy na nim zapisać identyfikator kontrahenta oraz wszelkie wymagane dane dla danego typu dokumentu. Mimo iż logika tworzenia baz danych sugerowałaby zapisanie samego identyfikatora, to w sytuacji, gdy kontrahent zmieni jakąś składową nagłówka (np. zmieni adres) baza może przejść w stan niespójny. W takiej sytuacji dopuszczamy sytuacje, w której dokument zapisany w bazie danych może być różny od jego wydrukowanej wersji, co jest z kolei niedozwolone. Tak, więc idealna baza danych to nie tylko zbiór niepowtarzających się faktów, ale również zbiór faktów nastawiony na minimalizację powtórzeń pozostający w spójności z obszarem analizy w okresie czasu.
Zdarzenia, które powodują zmianę stanu, są w terminologii baz danych nazywane transakcjami. Transakcja zmienia bazę danych z jednego stanu w kolejny (nowy). Nowy stan jest wprowadzany przez stwierdzenie faktów, które stają się prawdziwe oraz przez zaprzeczenie faktów, które przestają być prawdziwe [Beynon-Davies 2003].
Większość danych jest przechowywana w bazie danych po to, aby spełnić pewne potrzeby związane z organizacją jakiejś struktury. Do wykonywania takiej operacji na bazie danych są potrzebne dwa rodzaje funkcji: aktualizujące i zapytań. Funkcje aktualizujące dokonują zmian danych (przeprowadzają transakcje). Funkcje zapytań wydobywają dane
z bazy danych niedokonując żadnych zmian w strukturze danych. Akcja danej funkcji aktualizującej może spowodować, że warunki innej funkcji aktualizującej staną się prawdziwe. W tym przypadku mówimy, że pierwsza funkcja aktualizująca „wyzwoliła” zmianę stanu. W ten sposób z transakcji „zewnętrznej” możemy uruchomić kaskadowo transakcje „wewnętrzne”.
Drugim podstawowym typem funkcji bazy danych jest funkcja zapytania. Nie modyfikuje ona w żaden sposób bazy danych, ale jest używana głównie do sprawdzania, czy pewien fakt lub grupa faktów jest spełniona w danym stanie bazy danych
[Beynon-Davies 2003].
Każdy system bazy danych musi używać jakiegoś formalizmu reprezentacji. Patrick Henry Winston zdefiniował formalizm reprezentacji, jako zbiór składniowych
i semantycznych konwencji, które umożliwiają opisywanie rzeczy. Składnia reprezentacji określa reguły łączenia symboli w celu kreowania wyrażeń w formalizmie reprezentacji. Semantyka reprezentacji określa, w jaki sposób takie wyrażenia mają być rozumiane, innymi słowy, w jaki sposób wprowadza się ich znaczenie. W terminologii baz danych idea formalizmu reprezentacji odpowiada pojęciu modelu danych. Model danych dostarcza twórcom baz danych zbioru reguł, za pomocą, których mogą skonstruować system bazy danych. Istnieje wiele różnych modeli danych. Najbardziej powszechny jest relacyjny model danych, który oferuje bardzo elastyczny sposób reprezentowania faktów, ale nie dostarcza łatwego sposobu reprezentowania zawiłości funkcji aktualizujących w systemach baz danych. Obiektowe (post-relacyjne) bazy danych oferują dobrą notację reprezentowania funkcji aktualizujących w systemach baz danych, ale ich dużą wadą jest brak jednolitości dostępnych implementacji [Beynon-Davies 2003]. Należy także zauważyć, iż najpopularniejszy (relacyjny) model danych ze względu na drobne różnice w implementacji u konkretnych dostawców oprogramowania bazodanowego napotyka podobne trudności, co modele post-relacyjne. Skutkuje to dużymi trudnościami przy przenoszeniu logiki bazodanowej pomiędzy dostawcami, a czasem nawet pomiędzy różnymi wersjami oprogramowania tego samego dostawcy.
Baza danych może być używana tylko przez jedną osobę lub jeden system użytkowy. Jednakże w większości przedsiębiorstw wiele baz danych jest używanych przez wielu użytkowników. Korzystanie z wspólnych danych stanowi główną cechę większości systemów baz danych.
Z definicji w bazie danych z wieloma użytkownikami musi istnieć metoda obsługi przypadku, gdy kilka osób lub systemów użytkowych chce uzyskać dostęp do tych samych danych w tym samym czasie. Problem ten nosi nazwę współbieżności
[Beynon-Davies 2003].
Weźmy pod uwagę sytuację, gdy jeden użytkownik rejestruje np. studenta na określonym kierunku studiów. W tej samej chwili inny użytkownik usuwa ze zbioru aktualnie oferowanych kierunków, kierunek na który właśnie jest rejestrowany student. Jest oczywiste, że w tej chwili, gdy pierwszy użytkownik wprowadza fakt rejestracji, drugi użytkownik mógłby zanegować fakt istnienia tego faktu. Baza danych zostałaby w stanie niespójnym.
W takim systemie bazy danych muszą istnieć sposoby radzenia sobie z tego typu sytuacjami
[Beynon-Davies 2003]. Moim zdaniem należy też zwrócić uwagę, iż mechanizmy panowania nad problemem współbieżności implementowane są przez każdego dostawcę inaczej. Dlatego też już na etapie projektowania bazy należy wybrać dostawcę systemu bazodanowego
i uwzględnić dany mechanizm. Nawet subtelne różnice mogą okazać się przeszkodą sprawiającą, że dany system stanie się bezużyteczny dla końcowego użytkownika.

T SQL – definicja, teoria

Transakcyjny SQL (ang. Transact-SQL, T-SQL) jest rozszerzeniem języka SQL umożliwiającym tworzenie konstrukcji takich jak pętle, instrukcje warunkowe oraz zmienne. Powstałe bloki kodu można osadzać w bazie danych pod postacią procedur bądź funkcji. Jest używany głównie do tworzenia wyzwalaczy (ang. triggers) procedur i funkcji składowanych
w bazie. Został stworzony przez Sybase i wbudowany do serwerów SQL tej firmy, później prawa kupiła firma Microsoft i wykorzystuje ten język w kolejnych wersjach MS SQL Server. Język T-SQL pełni podobną rolę w produktach bazodanowych Microsoftu jak język PL/SQL w bazach Oracle. Zrozumienie tych dwóch języków pozwala poznać różnice implementacji
i działania wielu mechanizmów w poszczególnych bazach [Internet: http://pl.wikipedia.org].

PL/SQL – definicja, teoria

PL/SQL jest to proceduralne (a czasem obiektowe) rozszerzenie języka SQL udostępniane przez Oracle i przeznaczone wyłącznie do obsługi produktów tej firmy. PL/SQL wywodzi się z języka Ada a twórcy PL/SQL zapożyczyli wiele pomysłów z tego języka [Urman, Hardman, McLauglin 2008].
PL/SQL to język chroniony prawami autorskimi. Jest to język trzeciej generacji (3GL), który udostępnia konstrukty programistyczne podobne do innych języków klasy 3GL, włączając w to deklaracje zmiennych, pętlę, obsługę błędów itd. Obecnie PL/SQL można traktować jako język obiektowy [Urman, Hardman, McLauglin 2008].
Omawiając Język PL/SQL warto wspomnieć o innych rozszerzeniach SQL oferowanych przez firmę Oracle. Dostawca obsługuje język SQL zgodnie ze standardami ANSI, jednak udostępnia także własną wersję – SQL*Plus. Dzięki SQL*Plus Oracle obsługuje dodatkowo polecenia i funkcje, których nie obejmują standardy. Wspomniane narzędzie dostępne jest w kilku postaciach: Wiersz poleceń uruchamiany z wiersza poleceń systemu Unix lub DOS. Graficzny interfejs użytkownika w programach SQL*Plus Client, SQL Worksheet, Enterprise Manager [Urman, Hardman, McLauglin 2008].

PL/SQL a SQL
SQL zapewnia kompletny dostęp do danych. Oznacza to, że można pobrać dowolne dane – po pewnym czasie (z pewnym opóźnieniem) i w wielu przypadkach w niedoskonały sposób. Nie ma gwarancji, co do wydajności oraz przede wszystkim aktualności lub dostępności danych. Sam SQL udostępnia niewiele funkcji. Do ograniczeń tradycyjnego SQL’a należy wymienić: przechodzenie w pętli po rekordach i manipulowania każdym z nich po kolei; zabezpieczenia kodu za pomocą szyfrowania i przechowywania kodu całkowicie po stronie serwera, a nie po stronie klienta; obsługi wątków; korzystania ze zmiennych, parametrów, kolekcji, rekordów, tablic, obiektów, kursorów, wyjątków, kolumn BFILE itd.
[Urman, Hardman, McLauglin 2008].
Dlatego też SQL pozostaje bardziej sposobem dostępu do bazy danych niż językiem programowania. PL/SQL rozpoczyna się w miejscu, w którym kończy się SQL,
i oferuje wspomniane wyżej funkcje, a także wiele innych możliwości
[Urman, Hardman, McLauglin 2008].
Prawie wszystkie operacje języka SQL można wykonać za pomocą PL/SQL. Od wersji Oracle 9iR1 parser języka PL/SQL jest taki sam jak parser SQL, co gwarantuje, że polecenia są traktowane tak samo niezależnie od tego, gdzie zostały wykonane. W starszych wersjach Oracle zdarzały się sytuacje, w których instrukcje języka SQL były interpretowane zupełnie inaczej [Urman, Hardman, McLauglin 2008].

PL/SQL a JAVA
Bazy danych Oracle 8i i nowsze obejmują obsługę języka Java oraz procedur składowanych tego języka. PL/SQL jest i zawsze był ściśle zintegrowany z bazą danych Oracle. Firma Oracle nieustannie usprawnia wydajność tego języka, dodając i zwiększając tę integrację, poprzez nowe funkcje takie jak wbudowana kompilacja kodu PL/SQL. W trakcie wykonywania kodu system nie musi przekształcać kodu między językami PL/SQL a kodem maszynowym. Powoduje to znaczny wzrost wydajności – aż do 30% w porównaniu z trybem domyślnym obejmującym przekształcanie kodu. Kolejną zaletą PL/SQL jest jego zwięzłość. Chcąc przekształcić instrukcję SQL na blok języka PL/SQL wystarczy dodać instrukcję BEGIN na początku i instrukcję END na końcu. Nie można tego samego powiedzieć o języku Java. PL/SQL ma jeszcze kilka innych charakterystycznych cech. Obecnie PL/SQL korzysta
z tego samego parsera co SQL, dlatego zapewniona jest zgodność między interfejsami obu tych języków. Instrukcje PL/SQL można wykonywać z poziomu SQL. Do PL/SQL wciąż dodawane są funkcje obiektowe, co powoduje, że wiele przyczyny przechodzenia na język Java stają się nieaktualne [Urman, Hardman, McLauglin 2008].

SQL – definicja i teoria

SQL – Ustrukturyzowany język zapytań (ang. Structured Query Language (SQL)) służy do pobierania (instrukcja SELECT), wstawiania (instrukcja INSERT), aktualizowania (instrukcja UPDATE) i usuwania (instrukcja DELETE) danych [Celko 2008]. Można go używać do tworzenia i przechowywania obiektów oraz użytkowników, a także do kontrolowania praw dostępu do danych. Jest to język czwartej generacji (ang. fourth generation languages, 4GL), który ma być łatwy w użyciu i nauce. Język ten powstał na podstawie prac doktora E. F. Codda oraz firmy IBM we wczesnych latach 70. Instytut ANSI (ang. American National Standards Institute) uznaje język SQL i publikuje jego standardy [Tow 2004]. Instrukcje pobierania danych (ang. Select) pozwalają na wykonywanie operacji arytmetycznych oraz logicznych w trakcie wykonywania zapytań bez modyfikowania danych w bazie. Dodatkowo SQL pozwala na agregowanie danych, dzięki czemu w bardzo łatwy sposób można przedstawiać częściowo zinterpretowane dane w sposób zrozumiały dla człowieka
[Urman, Hardman, McLauglin 2008].

Opeatory relacyjne i logiczne

Pobieranie danych z bazy jest operowaniem na zbiorach.
Mamy dostępne kilka rodzajów operacji. Możemy je podzielić na 2 grupy.

Pierwsze to operatory relacyjne.
Equal – znak równości (=)
Not equal – znak różności (!=, <>)
Znak większości (>, >=)
Znak mniejszości (<, <=) Pomiędzy (between … and …) Nie pomiędzy (not between … and... ) W zbiorze ( in ) Poza zbiorem ( not in ) Jest null ( is null ) Nie jest null ( is not null ) Istnieje ( Exist ) Nie istnieje ( not exist ) W oparciu o nie możemy definiować warunki (where) np: select * from przyjaciele where wiek=22 lub: select * from przyjaciele where wiek in (13,45,6,7) Warto zwrócić uwagę jak jest realizowany operator between w konkretnych RDBMS. Czasem tworzy on przedziały otawrte czasem jednostronnie zamknięte lub obustronnie zamknięte. Operatory is (not) null - służą do porównywania wartości nieokreślonych. select * from przyjaciele where nazwisko = null jest błędne. Takie zapytanie nie zadziała poprawnie. Do wartości null (nieokreślonej) nie możemy przyrównywać. Możemy za to spytać czy wartość jest nie określona: select * form przyjaciele where nazwisko is null;

Operatory (not) in oraz (not) exist służą do analizowania zbiorów (najczęściej za pomocą podzapytań

select * from przyjaciele where kolor not in (select kolor from kolory)

Zapytanie zwróci przyjaciół którzy mają atrybut kolor który nie występuje w tabeli kolory.
W przypadku operatora exist(istnieje) jest sprawdzane czy jakiś warunek zostaje spełniony, jeśli tak nie jest pobierana wartość. Teoretycznie jest to szybszy sposób na wykonanie bardziej skomplikowanych zapytań.

Mamy jeszcze operatory logiczne,
najpopularniejsze to:

AND – logiczny iloczyn, wszystkie
argumenty muszą zwrócić TRUE.

select * from przyjaciele where wiek > 10 and wiek < 20;

tożsame w pewnych przypadkach z

select * from przyjaciele where wiek between 10 and 20;

select * from przyjaciele where wiek = 10 and imie = 'Janek'

możemy też stosować wykluczenia:

select * from przyjaciele where wiek= 10 and not imie='Janek'

co jest tożsame z:


select * from przyjaciele where wiek=10 and imie!= 'Janek'

lub:

select * from przyjaciele where wiek=10 and imie <> 'Janek'

Reasumując obydwa warunki muszą zostać spełnione by został zwrócony odpowiedni wiersz.
Oczywiście warunków może być więcej niż 2.

Kolejnym operatorem logicznym jest:

OR – Suma logiczna, co najmniej
jeden argument musi zwrócić TRUE

Mówiąc po ludzku or - lub, and - i
czyli jeden z 2 warunków musi zostać spełniony by wiersz znalazł się w wynikach np:

select * from przyjaciele where imie='Janek' or imie='Ania'

Warunkowanie or jest mniej wydajne niż 'and'. W niektórych sytuacjach lepiej użyć Unii (więcej o uniach można poczytać w kursie SQL w dziale złączenia).

Istnieją jeszcze operatory XOR ale ich użycie jest znikome więc nie będę ich tutaj omawiał.

Oczywiście można łączyć rodzaje warunków i je stopniować:

select * from przyjaciele where imie='Janek' or (nazwisko='Kowalski' and wiek > 15) and plec=0
or wynagrodzenie between 1000 and 10000

Powinny zostać zwrócone rekordy gdzie imie=Janek lub nazwisko kowalski mający równocześnie ponad 15 lat
i ma ustawiona plec =0 lub osoba z wynagrodzeniem w przedziale 1000 do 10000.

Widoki

Widok (perspektywa) – jest to zapisane w bazie danych nazwane zapytanie pobierające dane z jednej lub wielu encji(tabel) . Do widoku odwołujemy się tak jak do nazwy tabeli.

Create view jakis_widok as
Select kolumna1,kolumna2 from jakas_tabela;

Powstanie widok o nazwie jakis_widok, wykonanie zapytania:

Select * from jakis_widok;

Wyświetli nam dwie kolumny tabeli: jakas_tabela;

Główną zaletą widoków jest możliwość łatwego zapisania skomplikowanych zapytań oraz możliwość nadawania uprawnień do ograniczonej ilości danych (uprawnienia w Oracle).

Istnieje jeszcze widok zmaterializowany(W Oracle), służy on do zwiększenia wydajności kosztem aktualności danych. Podczas tworzenia widoku zmaterializowanego określa się interwał odświeżania danych w widoku. Co określony czas następuje ‘zrzucenie’ przeliczonych danych. Wywołanie widoku powoduje odczytanie ‘zrzuconych’ i już przeliczonych danych.

Nadpisywanie widoków jest realizowane w zależności od RDBMS. W przypadku oracle:

create or replace jakis_widok as
select * from nowa_tabela;

W przypadku Mssql:

Alter view jakis_widok as
select * from nowa_tabela;

W przypadku bazy Oracle należy pamiętać że widok będzie wykonywany z prawami jego twórcy. Oznacza to iż nie musimy nadawać uprawnień dla obiektów podrzędnych (np tabel z których korzysta widok). Reasumując wystarczy nadać prawo select (grant select on jakis_widok to jakis_user) by było można korzystać z widoku.
W przypadku MSSQL w większości przypadków należy nadać uprawnienia do elementów podrzędnych widoku.