Informacje ważne z praktycznego punktu widzenia, i z tego powodu godne przechowywania, bardzo często obejmują zbiór podobnych do siebie niewielkich porcji informacji. Często bywa też, że porcje te w pewien sposób odpowiadają odrębnym „obiektom”, które opisują za pomocą ustalonego zbioru cech przedmioty świata rzeczywistego (np. księgozbiór biblioteki) lub sfery działalności ludzkiej (np. umowy prawne), a także związki między tego typu obiektami (np. terminarz dyżurów pracowników).
Jest to sytuacja na tyle często spotykana i ważna, że w ramach technik informatycznych zostały wypracowane specjalne reguły i narzędzia. Zasady te abstrahują od znaczenia danych nadawanego przez ich właściciela (np. że przechowywane są dane osobowe), a odnoszą się do zasad efektywnego gospodarowania: zarządzania i udostępniania zbiorów danych.
Przez bazę danych będziemy rozumieć strukturę informacyjną przeznaczoną do przechowywania danych o złożonych obiektach i powiązaniach między nimi. Struktura taka musi zapewniać bezpieczne i trwałe przechowywanie informacji oraz udostępniać wybrane fragmenty swojej zawartości uprawnionym użytkownikom w dogodny dla nich sposób i w dogodnym dla nich czasie.
Dlaczego bazy danych, a nie np. pliki tekstowe lub dokumenty związane z jakąś aplikacją? Przede wszystkim dlatego, że użytkowanie bazy danych pozwala zapomnieć o szczegółach realizacyjnych i skupić się na istocie rzeczy, jaką jest zarządzanie zestawem danych. Pozwala na dostęp do danych różnymi sposobami, za pomocą wielu aplikacji użytkowych. Pozwala na współużytkowanie jednego zestawu danych przez wielu użytkowników jednocześnie — w przypadku zwykłego pliku, nawet udostępnianego w sieci, jednoczesna edycja przez kilku użytkowników łatwo doprowadziłaby do uszkodzenia jego zawartości. Pozwala wreszcie na zróżnicowanie praw dostępu do przechowywanych danych: poszczególni użytkownicy mogą wprowadzać, modyfikować, oglądać fragmenty bazy danych stosownie do przydzielonych im przywilejów.
Informacje o świecie rzeczywistym, jego obiektach i związkach między nimi da się porządkować, formalizować i przechowywać na wiele różnych sposobów. Nic więc dziwnego, że istnieje wiele rodzajów baz danych, a każdy z nich nadaje się lepiej lub gorzej do odwzorowania poszczególnych typów danych i zależności.
W bardziej potocznym ujęciu terminu baza danych
używa się do określenia
samej zawartości takiego zbioru informacji. Zawartość ta na ogół zmienia się
w czasie, w miarę jak dane podlegają aktualizacji.
W ujęciu technicznym baza danych
ma jeszcze jedno znaczenie:
jest nim system informatyczny, służący do zarządzania bazami danych.
W precyzyjnej terminologii system taki nosi nazwę
systemu zarządzania bazami danych
(Database Management System, DBMS).
Konkretny egzemplarz takiego systemu, będący w stanie aktywności
(tj. uruchomiony i przyjmujący zlecenia od użytkowników),
określa się mianem serwera baz danych.
Istnieje wiele koncepcji reprezentowania informacji w systemie bazodanowym. W ciągu kilkudziesięciu lat historii systemów baz danych koncepcje te ewoluowały i przenikały się wzajemnie. Zamiast wprowadzać formalne definicje, porównajmy sposoby, jakimi pewien nieskomplikowany zestaw informacji może zostać przedstawiony w środowiskach baz danych: kartotekowej, hierarchicznej, sieciowej, relacyjnej i obiektowej.
Jedna tabela o luźno zobowiązującej strukturze. Przykład: książka adresowa z dowolnymi zapisami na temat figurujących w niej osób.
Każda jednostka zapisu może kierować do jednostek podrzędnych. Przykłady: przechowywanie struktury organizacyjnej przedsiębiorstwa, system plików.
Składają się z zestawu powiązanych ze sobą tabel o znormalizowanej strukturze.
Mogą przechowywać informacje o obiektach dowolnego typu, w tym także definiowanych na potrzeby konkretnej bazy danych. W szczególności obiektami mogą być dane multimedialne, ale także tabele bazodanowe, a nawet całe bazy danych.
Obiektowe bazy danych pozwalają aplikacjom klienckim importować zawartość w postaci gotowych struktur danych, nie różniących się od struktur deklarowanych za pomocą języków programowania. Podnosi to ich atrakcyjność w wybranych zastosowaniach profesjonalnych.
Nie są związane z jednym serwerem. Umożliwiają dotarcie do informacji rozproszonych w sieci rozległej, dostępnej poprzez odpowiednie mechanizmy adresowania. Przykłady: serwis nazw domenowych DNS w sieci TCP/IP, zasoby WWW.
Imie-psa
— ktoś może nie mieć psa, a ktoś inny może mieć ich więcej).
Układ tabel powinien odzwierciedlać relacje — czyli mówiąc z grubsza zależności między danymi —
w jednej z ich tzw. postaci normalnych (zagadnienie to zostanie sprecyzowane w trakcie wykładu).
Zgodność taka umożliwia przechowywanie minimalnego zestawu danych i unikanie komplikacji
związanych z zarządzaniem danymi.
Zbiory rekordów zbudowanych według jednego wzoru, przechowywane trwale w bazie danych, będziemy określać słowem tabele.
Prezentacje wybranego wycinka informacji w typowym układzie interesującym dla użytkowników noszą nazwę perspektyw. Mają one budowę relacyjną, podobnie jak tabele, ale zawierają powtarzające się (więc nadmiarowe) elementy i nie są przechowywane w trwałej postaci. Perspektywa jest na bieżąco budowana z zawartości tabel zgodnie z zapytaniem użytym do jej zdefiniowania. Przechowywanie perspektyw w pamięci serwera bazy danych odciąża go z konieczności wielokrotnego konstruowania tych samych tabel wynikowych przy powtarzających się zapytaniach.
Zestawienia, w których użytkownik otrzymuje wyciąg z bazy danych w interesującym go układzie, noszą nazwę raportów. Złożone zestawienia są tworzone na podstawie informacji zapisanych w bazie danych, bez wykorzystania jakichkolwiek informacji z zewnątrz. Baza umożliwia uzyskanie zestawienia danych w dowolnym interesującym użytkownika układzie treściowym i graficznym.
Na przykład raporty z bazy danych dotyczącej miejskiej sieci komunikacyjnej mogą dotyczyć m.in.:
Sama baza danych musi być zaprojektowana w taki sposób, by wszystkie te odpowiedzi dało się uzyskać automatycznie z pewnego minimalnego zestawu informacji pierwotnych.
Widać stąd, że baza danych jest rzeczą o wiele bardziej elastyczną i skomplikowaną niż wydruki i tabele zestawieniowe, do których lektury przywykliśmy jako użytkownicy. Baza jako system musi umożliwiać ich automatyczne generowanie.
W zamieszczonym niżej obszernym przykładzie ilustrujemy podstawowe koncepcje normalizowania układu tabel w relacyjnej bazie danych. Zbiór informacji jest w nim stopniowo przekształcany od wstępnej, „naiwnej” postaci w kierunku coraz pełniejszej normalizacji. Poszczególne etapy tych przekształceń są opatrzone komentarzem.
W docelowym projekcie każda dana prosta i każda zależność przechowywana w bazie będzie zapisana dokładnie jeden raz.
Kompletny opis normalizacji relacyjnych baz danych można znaleźć w literaturze przedmiotu.
Zaczniemy od pojedynczej tabeli zawierającej osobiste dane adresowe i kontaktowe.
Dane w treści przykładu są całkowicie fikcyjne.
Pierwsza propozycja to prosta tabela kartotekowa pozwalająca na swobodną notację. Tabela nie posiada klucza. Wobec tego nie istnieje formalne kryterium, które gwarantowałoby tożsamość poszczególnych wpisów, a w konsekwencji np. jednoznaczność wyników wyszukiwania. Takie bazy danych nie mogą istnieć niezależnie od inteligentnego właściciela, który zna i w pełni kontroluje ich zawartość. Są więc w pewnym sensie niekompletne.
Dowolność w traktowaniu zawartości pola Telefon
sprawia, że
odnaleziona w tabeli informacja nie nadaje się do natychmiastowego wykorzystania;
trzeba ją jeszcze przeanalizować. Ponieważ kryteria tej analizy nie są do końca ustalone,
może ją przeprowadzić tylko inteligentny podmiot (czyli np. właściciel notesu).
Imię | Nazwisko | Adres | Telefon | Uwagi |
---|---|---|---|---|
Adam | Kowalski | 01-234 Poznań, Poznańska 55 | 123456789 | imieniny na Wojciecha |
Adam | Kowalski | 12-345 Gniezno, Gnieźnieńska 66 | 123456780 099 3378900 |
Ten sam zestaw danych uzupełniony o pole Nick
pełniące rolę klucza.
Ten typ klucza jest określany jako klucz zewnętrzny, gdyż ma on odpowiednik
w świecie poza bazą danych. Jak w każdym kluczu, także i tu wartości w kolumnie nie mogą
się powtarzać.
Nick | Imię | Nazwisko | Adres | Telefon | Uwagi |
---|---|---|---|---|---|
Wujo | Adam | Kowalski | 01-234 Poznań, Poznańska 55 | 123456789 | imieniny na Wojciecha |
Gniady | Adam | Kowalski | 12-345 Gniezno, Gnieźnieńska 66 | 123456780 099 3378900 |
Poleganie na kluczu zewnętrznym nie jest korzystne. W rzeczywistości może się okazać, że… nie jest on kluczem (łatwo wyobrazić sobie dwie różne osoby o tym samym pseudonimie), albo że jego wartości się zdezaktualizowały (bo np. ktoś używa dzisiaj innego pseudonimu, niż dawniej). Dlatego lepiej jest, kiedy tabela posiada swój własny klucz, nie oznaczający niczego poza tożsamością rekordu.
Klucz | Nick | Imię | Nazwisko | Adres | Telefon | Uwagi |
---|---|---|---|---|---|---|
1 | Wujo | Adam | Kowalski | 01-234 Poznań, Poznańska 55 | 123456789 | imieniny na Wojciecha |
2 | Gniady | Adam | Kowalski | 12-345 Gniezno, Gnieźnieńska 66 | 123456780 099 3378900 |
Stopień uporządkowania zapisów zwany pierwszym poziomem normalizacji zakłada, że dana przechowywana w pojedynczym polu jest niepodzielna.
W naszej tabeli pole Telefon
nie było niepodzielne, ponieważ
godziliśmy się, by przechowywać w nim kilka numerów telefonów.
Trzeba to zmienić.
Klucz | Nick | Imię | Nazwisko | Adres | Telefon | Uwagi |
---|---|---|---|---|---|---|
1 | Wujo | Adam | Kowalski | 01-234 Poznań, Poznańska 55 | 123456789 | imieniny na Wojciecha |
2 | Gniady | Adam | Kowalski | 12-345 Gniezno, Gnieźnieńska 66 | 123456780 | praca |
3 | Gniady | Adam | Kowalski | 12-345 Gniezno, Gnieźnieńska 66 | 099 3378900 | dom |
Zauważmy, że pojedynczy rekord takiej tabeli nie opisuje już wszystkich ujętych w bazie właściwości danej osoby. Jednak każdy wpis adresowy jest kompletny.
Możliwy jest też inny schemat, polegający na wprowadzeniu kilku kolumn z numerami telefonów:
Klucz | Nick | Imię | Nazwisko | Adres | Telefon 1 | Telefon 2 | Uwagi |
---|---|---|---|---|---|---|---|
1 | Wujo | Adam | Kowalski | 01-234 Poznań, Poznańska 55 | 123456789 | imieniny na Wojciecha | |
2 | Gniady | Adam | Kowalski | 12-345 Gniezno, Gnieźnieńska 66 | 123456780 | 099 3378900 | pierwszy telefon do domu, drugi do pracy |
Jest to układ znacznie mniej korzystny. Nie ma reguły, która zabraniałaby danej osobie posiadać większą liczbę numerów telefonów. W takim przypadku trzeba by dodać trzecią kolumnę danych, a dalej czwartą, piątą itd. Problem polega na tym, że w chwili tworzenia tabeli nie wiadomo, jakie wartości będą w niej przechowywane, zaś arbitralne ograniczenia nie istnieją.
Sytuacja, w której układ kolumn trzeba modyfikować z powodu potrzeby dopisania nowych danych, jest nie do przyjęcia. Taka tabela jest za mało elastyczna.
Sytuacja, w której dane o tym samym znaczeniu są przechowywane w kilku różnych kolumnach, również jest nie do przyjęcia. Przeszukiwanie takiej tabeli jest bardzo utrudnione wskutek komplikacji z wyborem kolumn.
Podobnie nie do przyjęcia jest sytuacja, w której pewna część tabeli pozostaje pusta. Posiadanie przez przynajmniej jedną osobę 4 numerów telefonów zmuszałoby nas do tworzenia czterech kolumn, jednak osoby posiadające mniej numerów miałyby w swoich rekordach puste pola, które nic nie wyrażają, i których nie sposób się pozbyć.
Pole Adres
w zupełności wystarcza dla potrzeb
osobistej książki telefonicznej, ale wyobrażalna jest sytuacja,
w której zajdzie potrzeba analizowania części składowych adresu.
Dlatego rozbijemy adres na następujące części:
Kod pocztowy
,
Miejscowość
,
Ulica
,
Numer domu
.
Klucz | Nick | Imię | Nazwisko | Kod pocztowy | Miejscowość | Ulica | Numer domu | Telefon | Uwagi |
---|---|---|---|---|---|---|---|---|---|
1 | Wujo | Adam | Kowalski | 01-234 | Poznań | Poznańska | 55 | 123456789 | imieniny na Wojciecha |
2 | Gniady | Adam | Kowalski | 12-345 | Gniezno | Gnieźnieńska | 66 | 123456780 | praca |
3 | Gniady | Adam | Kowalski | 12-345 | Gniezno | Gnieźnieńska | 66 | 099 3378900 | dom |
O tabelach przedstawionych w tej i poprzedniej sekcji możemy powiedzieć, że są w pierwszej postaci normalnej.
Tworząc tabelę adresową w pierwszej chwili mieliśmy jasny zamiar: jeden jej rekord miał zawierać informacje o pojedynczej osobie i jej atrybutach. Czasami zdarzało się, że danej osobie przysługiwały dwie lub więcej wartości danego atrybutu. Pierwszy poziom normalizacji wymaga, żeby te wartości były wpisane do osobnych pól.
Wskutek tego, pierwotny układ rekord ↔ osoba został zaburzony. Po korekcie każda osoba i jej adres pojawia się w tabeli tyle razy, ile ma telefonów. Takie dublowanie danych jest niekorzystne, gdyż niepotrzebnie obciąża pamięć, może też prowadzić do niespójności podczas aktualizacji.
W naszej tabeli kluczem własnym jest kolumna Klucz
.
Rolę klucza może pełnić także zespół kolumn (Nick
, Telefon
).
Jest to przykład tzw. klucza złożonego.
W tabelach o drugim poziomie normalizacji eliminowane są możliwości tych powtórzeń, które wynikają z zależności od części klucza złożonego.
W naszej tabeli pola:
Imię
,
Nazwisko
,
Miejscowość
,
Kod pocztowy
,
Ulica
,
Numer domu
,
zależą wyłącznie od pola Nick
— są one bowiem atrybutami
konkretnej osoby. Tabela ta nie jest więc znormalizowana na poziomie drugim.
Pole Uwagi
zależy od klucza złożonego jako całości.
Normalizacja będzie polegać na rozbiciu jednej dużej tabeli na kilka mniejszych. W każdej z nich będzie obowiązywać nich zasada: jeżeli istnieje zależność, to zawsze od klucza jako całości. Proponujemy następujący podział:
Klucz | Nick | Imię | Nazwisko | Kod pocztowy | Miejscowość | Ulica | Numer domu | Uwagi |
---|---|---|---|---|---|---|---|---|
1 | Wujo | Adam | Kowalski | 01-234 | Poznań | Poznańska | 55 | imieniny na Wojciecha |
2 | Gniady | Adam | Kowalski | 12-345 | Gniezno | Gnieźnieńska | 66 |
Klucz | Klucz osoby | Telefon | Uwagi |
---|---|---|---|
1 | 1 | 123456789 | |
2 | 2 | 123456780 | praca |
3 | 2 | 099 3378900 | dom |
Tym sposobem niektóre rodzaje powtórzeń danych, nieuniknione w poprzednich wersjach tabeli, zostały wyeliminowane. Ceną, jaką trzeba było za to zapłacić, jest przejście od bazy kartotekowej składającej się z jednej tabeli, do bazy relacyjnej zawierającej większą liczbę współpracujących ze sobą tabel.
W tym momencie jest jasne, jakie związki są reprezentowane
w poszczególnych tabelach.
Tabela Osoby
kataloguje osoby jako obiekty.
W tabeli Telefony
obiektami są przypisania
konkretnej osobie konkretnego numeru telefonu.
Jest to objaw korzystny: każda tabela bazodanowa winna
odzwierciedlać tylko jeden rodzaj zależności między danymi.
W związku z rozbiciem zbioru danych na dwie tabele pojawił się nowy problem.
Pole Klucz
w tabeli Osoby
może przyjąć w nowo tworzonym
rekordzie dowolną nie używaną dotychczas wartość. W przypadku pola Klucz osoby
w tabeli Telefony
rzecz ma się inaczej. Jego sensownymi wartościami są tylko
wartości aktualnie znajdujące się w kolumnie Klucz
tabeli Osoby
.
Mówimy, że Klucz osoby
jest kluczem obcym związanym z kluczem własnym
tabeli Osoby
. Takie stwierdzenie jest niezbędne dla zapewnienia spójności
bazy danych. Ograniczenia tego typu noszą nazwę więzów referencyjnych.
W tabeli Osoby
rolę klucza pełni pole Klucz
.
Każda osoba ma jednoznacznie przypisany adres, zatem można powiedzieć,
że znajomość klucza determinuje znajomość adresu:
numeru kodu, nazwy miejscowości, nazwy ulicy i numeru domu.
Jednocześnie jest faktem, że numer kodu pocztowego pozwala poznać nazwę miejscowości.
Zatem nazwa miejscowości, mimo że zależy od klucza, nie zależy od niego bezpośrednio:
można do niej dojść analizując związki
Klucz
→ Kod pocztowy
→ Miejscowość
.
O tabeli mówimy, że jest w trzeciej postaci normalnej, kiedy nie istnieją w niej zależności pośrednie. Każda dana, o ile nie jest częścią klucza, musi zależeć od klucza jako całości, i nie może zależeć od niczego innego.
Normalizację do poziomu trzeciego przeprowadza się,
podobnie jak poprzednią, za pomocą rozbicia tabeli na kilka części.
W naszym przypadku pole Kod pocztowy
powinno zostać przeniesione
do jednej z powstałych tabel, która przypisywałaby je ulicom bądź ich fragmentom.
Zanim zostanie to zrobione, trzeba jednak uporządkować składniki adresów tak, by spełniały warunki drugiego poziomu normalizacji. W tym celu wyodrębnimy tabelę przechowującą spis miejscowości oraz tabelę ze spisem ulic.
Klucz | Miejscowość |
---|---|
1 | Gniezno |
2 | Miękinia |
3 | Poznań |
Klucz | Klucz miejscowości | Ulica |
---|---|---|
1 | 1 | Poznańska |
2 | 1 | Gnieźnieńska |
3 | 2 | Poznańska |
4 | 2 | Gnieźnieńska |
5 | 3 | Poznańska |
6 | 3 | Gnieźnieńska |
Zauważmy, że ulica jako obiekt opisany w tabeli Ulice
„wie”,
dzięki użyciu klucza obcego, w jakiej miejscowości się znajduje. Tym samym, nadając
ulicom „osobowość”, usunęliśmy z bazy jeszcze jedną — choć nie tak
łatwą do wykrycia — zależność pośrednią: fakt istnienia w danej miejscowości
ulicy o danej nazwie mógł być przechowywany wielokrotnie.
Negatywnym skutkiem przyjętych rozwiązań jest fakt, że adres może być wpisany do bazy jedynie wtedy, kiedy występuje w nim składnik Ulica.
Każdej osobie przypiszemy adres w postaci pary składającej się z klucza ulicy oraz numeru domu.
Klucz | Nick | Imię | Nazwisko | Klucz ulicy | Numer domu | Uwagi |
---|---|---|---|---|---|---|
1 | Wujo | Adam | Kowalski | 5 | 55 | imieniny na Wojciecha |
2 | Gniady | Adam | Kowalski | 2 | 66 |
Klucz | Klucz osoby | Telefon | Uwagi |
---|---|---|---|
1 | 1 | 123456789 | |
2 | 2 | 123456780 | praca |
3 | 2 | 099 3378900 | dom |
Na koniec zostawiliśmy kody pocztowe. Jako nadbudowa w stosunku do miejscowości i ulic są one przechowywane w osobnej tabeli, która korzysta z katalogu ulic.
Klucz | Kod pocztowy | Klucz ulicy | Od numeru | Do numeru | Strona |
---|---|---|---|---|---|
1 | 01-234 | 5 | 1 | 100 | N |
2 | 01-236 | 5 | 1 | 100 | P |
3 | 12-344 | 2 | 1 | 50 | N |
4 | 12-345 | 2 | 51 | 100 | N |
5 | 12-346 | 2 | 1 | 100 | P |
W powyższym rozwiązaniu osoba nie ma przypisanego numeru kodu pocztowego. I bardzo dobrze. Adres posiada kod pocztowy niezależnie od istnienia osoby, która pod tym adresem mieszka, od ilości takich osób czy też od ich cech szczególnych.
Czwarty poziom normalizacji zilustrujemy opierając się na innym przykładzie. Jego pomysł zaczerpnięto z rozdziału 3. książki W. Cellarego i Z. Królikowskiego Wprowadzenie do projektowania baz danych (WNT, Warszawa 1988).
Naszym zadaniem jest przechowywanie informacji o wybranych kwalifikacjach pracowników pewnej firmy. Interesuje nas, jakimi językami obcymi władają pracownicy oraz jakie języki programowania mają opanowane.
Podobnie jak poprzednio, dane są całkowicie fikcyjne.
Główny problem, z jakim mamy tu do czynienia, jest następujący: każdy pracownik może znać wiele języków obcych i wiele języków programowania. Sama gwarancja, że tabele będą spełniać wymogi trzeciego poziomu normalizacji, nie wystarcza do efektywnego zarządzania taką bazą.
W dziale IT pracują następujący pracownicy:
Klucz | Imię | Nazwisko |
---|---|---|
1 | Adam | Kowalski |
2 | Anna | Nowak |
3 | Adam | Wróbel |
Następujący zapis kartotekowy, jak wiemy z lektury poprzedniego przykładu, nie spełnia postulatów pierwszego poziomu normalizacji:
Klucz | Imię | Nazwisko | Języki obce | Języki programowania |
---|---|---|---|---|
1 | Adam | Kowalski | angielski, niemiecki, rosyjski | C++, C# |
2 | Anna | Nowak | angielski, francuski | C++, Java, Python |
3 | Adam | Wróbel | francuski | C++, C#, Java, PHP |
Stosunkowo nietrudno będzie sprowadzić tę tabelę do trzeciej postaci normalnej. Dla uproszczenia nie będziemy wprowadzać kluczy języków; zamiast tego będziemy stosować ich nazwy w roli kluczy.
Klucz | Imię | Nazwisko |
---|---|---|
1 | Adam | Kowalski |
2 | Anna | Nowak |
3 | Adam | Wróbel |
Klucz | Klucz pracownika | Język obcy | Język programowania |
---|---|---|---|
1 | 1 | angielski | C++ |
2 | 1 | niemiecki | C# |
3 | 1 | rosyjski | |
4 | 2 | angielski | C++ |
5 | 2 | francuski | Java |
6 | 2 | Python | |
7 | 3 | francuski | C++ |
8 | 3 | C# | |
9 | 3 | Java | |
10 | 3 | PHP |
Powyższy zestaw tabel jest w trzeciej postaci normalnej. Jednak jego zawartość nie jest satysfakcjonująca.
Przede wszystkim nie bardzo wiadomo, czego dotyczy pojedynczy rekord tabeli
Kwalifikacje
.
Na przykład w rekordzie 1. występuje para (angielski, C++),
Nie ma żadnego sensownego związku między tymi dwiema wartościami, oprócz tego,
że istnieje pewien pracownik, który zna m.in. język angielski
i jednocześnie umie programować m.in. w C++.
Po drugie, w tabeli nie są zapisane wszystkie możliwe układy kwalifikacji posiadanych przez pracowników. Na przykład nie ma rekordu, który stwierdzałby istnienie pracownika mówiącego po niemiecku, umiejącego programować w C++, i to mimo faktu, że taki pracownik istnieje. Niektóre zestawy danych zostały zatem bez powodu wyróżnione.
Po trzecie, w tabeli pojawiły się liczne puste pola, do których nie da się wpisać żadnej sensownej wartości. Są one konsekwencją faktu, że dany pracownik zna inną liczbę języków obcych, niż języków programowania.
Gdyby chcieć pozbyć się wymienionych niedogodności, trzeba by zapisać w tabeli wszystkie pary umiejętności, jakimi pracownicy dysponują. Taka tabela byłaby bardzo długa i w większości składałaby się z powtórzeń:
Klucz | Klucz pracownika | Język obcy | Język programowania |
---|---|---|---|
1 | 1 | angielski | C++ |
2 | 1 | angielski | C# |
3 | 1 | niemiecki | C++ |
4 | 1 | niemiecki | C# |
5 | 1 | rosyjski | C++ |
6 | 1 | rosyjski | C# |
7 | 2 | angielski | C++ |
8 | 2 | angielski | Java |
9 | 2 | angielski | Python |
10 | 2 | francuski | C++ |
11 | 2 | francuski | Java |
12 | 2 | francuski | Python |
13 | 3 | francuski | C++ |
14 | 3 | francuski | C# |
15 | 3 | francuski | Java |
16 | 3 | francuski | PHP |
Na przykład fakt, że Adam Wróbel zna język francuski, jest w niej odnotowany aż czterokrotnie.
Tabela Kwalifikacje
jest niedobra, gdyż próbuje się w niej wyrazić
zbyt wiele związków. Rozwiązanie polega na rozbiciu jej na dwie osobne tabele,
z których jedna będzie wyrażać kwalifikacje dotyczące znajomości języków obcych,
a druga — znajomości języków programowania.
Klucz | Imię | Nazwisko |
---|---|---|
1 | Adam | Kowalski |
2 | Anna | Nowak |
3 | Adam | Wróbel |
Klucz | Klucz pracownika | Język obcy |
---|---|---|
1 | 1 | angielski |
2 | 1 | niemiecki |
3 | 1 | rosyjski |
4 | 2 | angielski |
5 | 2 | francuski |
6 | 3 | francuski |
Klucz | Klucz pracownika | Język programowania |
---|---|---|
1 | 1 | C++ |
2 | 1 | C# |
3 | 2 | C++ |
4 | 2 | Java |
5 | 2 | Python |
6 | 3 | C++ |
7 | 3 | C# |
8 | 3 | Java |
9 | 3 | PHP |
Jest to jedynie jedno z możliwych sensownych rozwiązań. Inna, bardziej elastyczna propozycja, polegałaby na stworzeniu kategorii „sfera kwalifikacji”, i na powiązaniu znajomości języków obcych ze sferą „języki obce”, zaś języków programowania — ze sferą „programowanie”.
Klucz | Imię | Nazwisko |
---|---|---|
1 | Adam | Kowalski |
2 | Anna | Nowak |
3 | Adam | Wróbel |
Klucz | Sfera |
---|---|
1 | języki obce |
2 | programowanie |
Klucz | Klucz pracownika | Klucz sfery kwalifikacji | Kwalifikacja |
---|---|---|---|
1 | 1 | 1 | angielski |
2 | 1 | 1 | niemiecki |
3 | 1 | 1 | rosyjski |
4 | 2 | 1 | angielski |
5 | 2 | 1 | francuski |
6 | 3 | 1 | francuski |
7 | 1 | 2 | C++ |
8 | 1 | 2 | C# |
9 | 2 | 2 | C++ |
10 | 2 | 2 | Java |
11 | 2 | 2 | Python |
12 | 3 | 2 | C++ |
13 | 3 | 2 | C# |
14 | 3 | 2 | Java |
15 | 3 | 2 | PHP |
Tak czy inaczej, dwie tabele nie wystarczą.
O zestawach danych, które są w trzeciej postaci normalnej, i w których dodatkowo niezwiązane ze sobą zależności są reprezentowane w osobnych tabelach, mówi się, że są w czwartej postaci normalnej.
Przypomnijmy, że argumentem wszystkich takich zależności może być tylko klucz tabeli.
Naukę języka zapytań można podjąć w oparciu o osobne podręczniki lub kursy. Jako uzupełnienie niniejszego opracowania oferujemy mini-podręcznik zatytułowany Ściąga z SQL.
Opis języka zapytań jest także standardową częścią dokumentacji współczesnych systemów bazodanowych. Trzeba jednak zdawać sobie sprawę, że taka dokumentacja dotyczy nie tyle standardu, co konkretnego systemu. Np. dialekty SQL opisane w dokumentacji systemów Oracle, PostgreSQL, MySQL, SQLite itd. będą się między sobą różnić rozszerzeniami standardu, czyli dopuszczalnymi w danym systemie dodatkowymi konstrukcjami językowymi, oraz niezaimplementowaniem części standardu (z pewnych konstrukcji nie da się skorzystać w bazach danego systemu, gdyż nie są rozumiane przez ich systemy zarządzania).
We współczesnych systemach bazodanowych funkcje udostępniania informacji i obsługi użytkownika są na ogół realizowane przez odrębne programy. System zarządzający bazą przyjmuje zlecenia napływające z zewnątrz za pośrednictwem pewnego protokołu komunikacyjnego, realizuje je i wysyła odpowiedź. Inny system, zwany klientem, służy użytkownikowi do formułowania zleceń, do wysyłania ich systemowi zarządzającemu oraz do odczytywania i interpretowania odpowiedzi. Jeżeli oba systemy korzystają z tego samego protokołu (czyli „rozmawiają w tym samym języku”), to komunikacja między nimi jest możliwa ku zadowoleniu użytkowników.
Zależnie od przeznaczenia, klient baz danych może być zorientowany na komunikację z jedną bazą danych, z wieloma bazami jednego systemu, lub z bazami różnych systemów zarządzania. Zlecenia wydawane przez użytkownika mogą mieć postać jawnie pisanych poleceń (obecnie najczęściej stosuje się do tego celu język SQL); mogą też być konstruowane za pomocą różnego rodzaju formularzy zapytań lub systemów menu. Rola formularzy polega na odizolowaniu użytkownika od szczegółów technicznych związanych z językiem zapytań; jednak zapytania i tak są generowane, tyle że pośrednio, przez program kliencki.