PSTI, edycja VII, 2006/07

Transkrypt

PSTI, edycja VII, 2006/07
----------------------------------------------------------------------------------------------------------------------------- ----------I. Wybieranie danych z wielu tabel.
Zadania obejmują wyszukiwanie danych z wielu tabel. Do budowy takich zapytań służy predykat JOIN, który
jest implementacją operatorów złączeń algebry relacji.
Znaleźć adresy oddziałów wypożyczalni samochodów, w których pracują poszczególni pracownicy. Aby
uzyskać te informacje, potrzebna jest lista pracowników oraz dane o miejscu zatrudnienia pracowników. W
bazie danych WYPAUT, dla każdego numeru miejsca (pracy pracownika) istnieje jeden wiersz w tabeli
MIEJSCA. DBMS odczytuje numer miejsca pracownika z tabeli PRACOWNICY, a potem przeszukuje tabele
MIEJSCA w celu znalezienia odpowiadającego temu numerowi wiersza, który opisuje dokładnie miejsce pracy,
tzn. adres, telefon i inne informacje. W języku baz danych SQL można to wyrazić poniższym zapytaniem:
Wykonać najpierw bez klauzuli WHERE
SELECT PRACOWNICY.NAZWISKO,
PRACOWNICY.STANOWISKO,
PRACOWNICY.DZIAL,
MIEJSCA.MIASTO,
MIEJSCA.ULICA
FROM PRACOWNICY,
MIEJSCA
WHERE PRACOWNICY.NR_MIEJSCA = MIEJSCA.NR_MIEJSCA
ORDER BY PRACOWNICY.NAZWISKO;
Takie zapytanie SQL nazywamy złączeniem (ang. join).
W zapytaniu tym:
w klauzuli SELECT specyfikujemy kolumny, które chcemy uzyskać, jako wynik zapytania,
w klauzuli FROM określamy nazwy złączanych tabel,
w klauzuli WHERE określamy warunki złączenia.
Składnia złączenia – predykat JOIN. Są dwa rodzaje składni zapytania złączeniowego.
Pierwszy przedstawiony został powyżej. Przy specyfikowaniu złączenia dwóch tabel, do poprawnego
wyświetlenia wyniku klauzula WHERE musi zawierać jeden warunek. Gdy złączamy trzy tabele klauzula
WHERE musi zawierać przynajmniej dwa warunki musza dotyczyć złączenia tabel, a pozostałe dotyczą wyboru
wierszy. Oto przykład:
SELECT WYPOZYCZENIA.NR_WYPOZYCZENIA,
PRACOWNICY.NAZWISKO,
PRACOWNICY.STANOWISKO,
PRACOWNICY.DZIAL,
MIEJSCA.MIASTO,
MIEJSCA.ULICA
FROM PRACOWNICY,
MIEJSCA,
WYPOZYCZENIA
WHERE PRACOWNICY.NR_MIEJSCA = MIEJSCA.NR_MIEJSCA
AND PRACOWNICY.NR_PRACOWNIKA = WYPOZYCZENIA.NR_PRACOW_WYP
AND MIEJSCA.MIASTO = ‘WARSZAWA’
ORDER BY PRACOWNICY.NAZWISKO;
Inny typ specyfikacji złączenia polega na zastosowaniu konstrukcji JOIN...ON:
SELECT PRACOWNICY.NAZWISKO,
PRACOWNICY.STANOWISKO,
PRACOWNICY.DZIAL,
MIEJSCA.MIASTO,
MIEJSCA.ULICA
FROM PRACOWNICY JOIN
MIEJSCA ON
PRACOWNICY.NR_MIEJSCA = MIEJSCA.NR_MIEJSCA
WHERE PRACOWNICY.STANOWISKO = ‘SPRZEDAWCA’
ORDER BY PRACOWNICY.NAZWISKO;
Jak widać powyżej, gdy używamy słowa kluczowego JOIN w klauzuli FROM, warunki złączenia musza być
wyspecyfikowane po klauzuli ON. W klauzuli WHERE można natomiast określić dodatkowe warunki, na
przykład wyboru wierszy.
Stosowanie aliasów w zapytaniu. Aliasy definiuje się w celu skrócenia nazwy tabeli. Przykładowo alias P może
wskazywać na tabele PRACOWNICY, a M może wskazywać tabele MIEJSCA:
SELECT P.NAZWISKO, P.STANOWISKO, P.DZIAL, M.MIASTO, M.ULICA
FROM PRACOWNICY P,
MIEJSCA M
WHERE
P.NR_MIEJSCA = M.NR_MIEJSCA
AND P.STANOWISKO = ‘SPRZEDAWCA’
ORDER BY P.NAZWISKO;
Wynik wykonania tego zapytania jest taki sam jak poprzedniego zapytania. Od tej chwili w przykładach
będziemy stosować aliasy dla nazw tabel.
Podsumowanie:
1. Dane mogą być wydobywane z jednej lub wielu tabel.
2. W zapytaniu wybierającym dane z przynajmniej dwóch tabel można użyć predykatu JOIN.
3. Jeżeli w zapytaniu, które wybiera dane z przynajmniej dwóch tabel, nie zostanie wyspecyfikowany warunek
po słowie kluczowym WHERE lub ON, to zwrócony wynik będzie iloczynem kartezjańskim.
4. W zapytaniach można używać aliasów zamiast nazw tabel.
Funkcje skalarne i arytmetyczne.
Wybieranie wyliczonych wartości. W zapytaniu SQL możemy użyć następujących funkcji skalarnych i
arytmetycznych w celu obliczenia wartości:
+ dodawanie
- odejmowanie
* mnożenie
/ dzielenie
Tych operatorów używamy też do budowy bardziej złożonych wyrażeń. W celu zaznaczenia kolejności
wykonywania działań można używać nawiasów.
SELECT P.IMIE, P.NAZWISKO, P.PENSJA, P.DODATEK,
P.PENSJA + P.DODATEK AS „DO_WYPLATY”
FROM PRACOWNICY P
WHERE P.PENSJA > 1100
ORDER BY P.NAZWISKO;
Wynik zapytania zawiera kolumnę obliczona, która jest suma kolumn PENSJA i DODTEK. Jeśli wartość którejś
z kolumn potrzebnych do obliczeń jest pusta (ma wartość NULL), to wartość pola związanego z obliczeniami na
tej wartości jest również pusta (NULL).
Aby nazwa kolumny wyliczonej mogła zawierać spacje, to nazwa ta musi być wziętą w cudzysłów:
SELECT P.IMIE, P.NAZWISKO, P.PENSJA, P.DODATEK,
P.PENSJA + P.DODATEK AS „DO WYPLATY”
FROM PRACOWNICY P
WHERE P.PENSJA > 1100
ORDER BY P.NAZWISKO;
Nazwa kolumny wyliczonej nie może wystąpić w klauzuli WHERE.
W niektórych systemach DBMS i zrealizowanych w nich odmianach języka SQL nazwy kolumny wyliczonej
nie można używać w klauzuli ORDER BY. Jest tak w InterBase. Wtedy należy używać numeru na liście
wyliczonej w klauzuli SELECT:
SELECT P.IMIE, P.NAZWISKO, P.PENSJA, P.DODATEK,
P.PENSJA + P.DODATEK AS DO_WYPLATY
FROM PRACOWNICY P
WHERE P.PENSJA > 1100
ORDER BY 5;
Porównanie daty. Kolumny typu daty lub czasu mogą być porównywane z innymi wartościami reprezentującymi
datę lub czas. Wartości przedstawiające datę lub czas musza być otoczone pojedynczym cudzysłowem. W
poniższym przykładzie zostaną wyświetlone dane pracowników zatrudnionych w lub po dacie 1998-01-01:
SELECT P.IMIE, P.NAZWISKO, P.DZIAL,
P.STANOWISKO, P.DATA_ZATR
FROM PRACOWNICY P
WHERE P.DATA_ZATR >= ‘1998-01-01’
ORDER BY P.NAZWISKO;
W DBMS IntrerBase funkcje SUBSTR trzeba uaktywnić. W tym celu deklarujemy funkcje, która będzie
pobrana z zewnętrznej biblioteki DLL dołączanej dynamicznie:
DECLARE EXTERNAL FUNCTION SUBSTR
CSTRING(80), SMALLINT, SMALLINT
RETURNS CSTRING(80) FREE_IT
ENTRY_POINT ‘IB_UDF_substr’ MODULE_NAME ‘ib_udf.dll’;
Po wykonaniu powyższego polecenia można przejść do opcji IBConsole, aby zobaczyć te funkcje, klikając w
panelu po lewej stronie na ikonie External Function.
Funkcja skalarna SUBSTR wybierania podłańcucha (dostępna w wybranych systemach DBMS).
Do wybierania podłańcucha służy funkcja SUBSTR. Aby z kolumny NAZWISKO wybrać ciągi znaków od
pozycji wskazywanej przez drugi argument do pozycji wskazywanej przez trzeci argument budujemy poniższe
zapytanie. Należy z naciskiem zaznaczyć, że funkcja ta ma inne znaczenie składni i inaczej działa w innych
systemach DBMS.
SELECT SUBSTR(K.NAZWISKO, 3, 4), K.NAZWISKO
FROM KLIENCI K;
Łączenie łańcuchów. Ciągi znaków można łączyć w całościowe łańcuchy wynikowe za pomocą operatora ||.
Co w innych odmianach SQL dla innych systemów DBMS można zastosować do łączenia łańcuchów specjalne
funkcje, np. w MySQL funkcje CONCAT, a w Microsoft SQLServer używamy znaku „+”.
Zatem określone zapytanie ma postać:



W DBMS
SELECT
W DBMS
SELECT
W DBMS
SELECT
InterBase
IMIE || ‘ ‘ || NAZWISKO AS KLIENT FROM KLIENCI;
MySQL
CONCAT(nazwisko, ' ', imie) AS dane_osobowe FROM klienci;
Microsoft SQLServer
IMIE + ‘ ‘ + NAZWISKO AS KLIENT FROM KLIENCI;
Podsumowanie:
1. Funkcje arytmetyczne mogą być używane w klauzuli SELECT oraz WHERE.
2. Kolumny wyliczone mogą być nazwane przez zastosowanie klauzuli AS.
3. Do zmiany reprezentacji danych służą funkcje skalarne.
4. W innych odmianach SQL dla innych systemów DBMS występuje bardzo dużo wbudowanych funkcji
skalarnych.
Funkcje kolumnowe i grupujące.
Funkcje kolumnowe. Do funkcji kolumnowych zalicza sie funkcje: SUM, AVG, MIN, MAX oraz COUNT. Funkcje
te używane są w klauzulach SELECT lub HAVING.
SUM – służy do obliczania sumy wartości w określonych kolumnach,
AVG – oblicza wartość średnia w kolumnie,
MIN – znajduje wartość minimalną,
MAX – znajduje wartość maksymalną,
COUNT – służy do zliczania wystąpień pewnej wartości w wierszach.
Poniższy przykład wyświetla całkowitą sumę wszystkich pensji pracowników, średnią pensje, minimalną pensje
oraz ilość pracowników:
SELECT SUM(P.PENSJA) AS PENSJA,
AVG(P.PENSJA) AS SREDNIA,
MIN(P.PENSJA) AS PENSJA_MIN,
MAX(P.PENSJA) AS PENSJA_MAX,
COUNT(*) AS ILOSC
FROM PRACOWNICY P;
Powyżej funkcja COUNT została użyta do zliczania wszystkich wierszy w tabeli (COUNT(*)). Może być ona
również użyta do zliczania wierszy nie zawierających powtarzających się wartości w kolumnie w kolumnach.
Przykładowo, możemy zliczyć liczbę działów i stanowisk w firmie:
SELECT COUNT(DISTINCT P.DZIAL) AS ILOSC_DZIALOW,
COUNT(DISTINCT P.STANOWISKO) AS ILOSC_STANOWISK
FROM PRACOWNICY P;
Funkcje kolumnowe można zastosować również na podzbiorze wierszy.
SELECT SUM(P.PENSJA) AS PENSJA,
AVG(P.PENSJA) AS SREDNIA,
MIN(P.PENSJA) AS PENSJA_MIN,
MAX(P.PENSJA) AS PENSJA_MAX,
COUNT(*) AS ILOSC
FROM PRACOWNICY P
WHERE P.DZIAL = ‘OBSLUGA KLIENTA’;
Klauzula GROUP BY. Grupuje wiersze o tej samej wartości wyszczególnionych kolumn. Funkcje agregujące
SQL (AVG, MAX, MIN, SUM, oraz COUNT) w klauzuli SELECT operują na każdej grupie osobno.
Następujące zapytanie pogrupuje wiersze według stanowiska:
SELECT P.STANOWISKO, SUM(P.PENSJA) AS PENSJA,
AVG(P.PENSJA) AS SREDNIA,
MIN(P.PENSJA) AS PENSJA_MIN,
MAX(P.PENSJA) AS PENSJA_MAX,
COUNT(*) AS ILOSC
FROM PRACOWNICY P
GROUP BY P.STANOWISKO
ORDER BY P.STANOWISKO;
Klauzula HAVING. Klauzula HAVING jest używana w GROPUP BY w celu ograniczenia wyświetlania grup.
Warunek szukania musi zawierać funkcje agregującą. Po zgrupowaniu wierszy przez klauzule GROUP BY,
klauzula HAVING wyświetla tylko te wiersze spośród zgrupowanych, które spełniają warunki wyszczególnione
w klauzuli HAVING. Klauzula HAVING może być użyta tylko wówczas, gdy w zapytaniu znajduje się klauzula
GROUP BY.
Aby wyświetlić wszystkich pracowników, którzy wypożyczyli samochody na łączną sumę powyżej 400zł
budujemy poniższe zapytanie:
SELECT P.NAZWISKO, SUM(W.CENA_JEDN)
FROM PRACOWNICY P,
WYPOZYCZENIA W
WHERE P.NR_PRACOWNIKA = W.NR_PRACOW_WYP
GROUP BY P.NAZWISKO
HAVING SUM(W.CENA_JEDN) > 400
ORDER BY P.NAZWISKO;
Podsumowanie:
1. Funkcje kolumnowe mogą być użyte tylko w klauzulach SELECT HAVING.
2. Klauzula SELECT może zawierać tylko funkcje kolumnowe oraz kolumny wskazane w klauzuli ORDER BY.
3. Klauzula HAVING może zawierać dowolne funkcje kolumnowe operujące na dowolnych kolumnach tabeli.
Kolumny te nie musza być wyspecyfikowane w klauzuli SELECT.
Klauzula UNION. Klauzula UNION pozwala na łączenie dwóch lub więcej wyników wykonania zapytania
SELECT. Zapoznamy się ze składnia polecenia UNION, oraz zasadami dla list w klauzuli SELECT oraz
różnicami miedzy klauzulą UNION i UNION ALL.
Łączenie wielu wyników zapytania.
Klauzula UNION łączy dwa lub więcej zapytania SELECT w jedną tabelę wynikowa. Klauzula SELECT musi
zwracać tę samą liczbę kolumn. Kolumny pokrywające się musza mieć te sama szerokość i typ danych. Nazwy
tych kolumn mogą być różne. Klauzula UNION łączy dwa zestawy wyników w jeden i jednocześnie usuwa
duplikaty. Powtarzające się wiersze umieszczane są w wyniku końcowym zapytania tylko raz, to znaczy
eliminowane są duplikaty w wyniku końcowym.
Poniższe zapytanie zwraca dane o imieniu i nazwisku wszystkich klientów i pracowników, których nazwiska
kończą się na „ski”. Tylko jedna osoba o imieniu i nazwisku Jan Kowalski występuje jednocześnie w tabeli
klientów i pracowników:
SELECT IMIE, NAZWISKO
FROM KLIENCI
WHERE NAZWISKO LIKE ‘%SKI’
UNION
SELECT IMIE, NAZWISKO
FROM PRACOWNICY
WHERE NAZWISKO LIKE ‘%SKI’;
Za każdym razem zapytania łączące wyniki z klauzula UNION wyświetlają wyniki posortowane rosnąco. Jeżeli
chcemy zawrzeć klauzule ORDER BY sortującą wyniki malejąco ze względu na NAZWISKO, to musi ona być
umieszczona na końcu zapytania.
Uwaga: W dialekcie języka SQL systemu DBMS InterBase, w klauzuli ORDER BY zamiast specyfikowania
nazwy kolumny NAZWISKO musimy wyspecyfikować numer pozycji tej kolumny na liście kolumn
wybieranych w SELECT (w poniższym przykładzie jest to 2). InterBase nie pozwala specyfikować w klauzuli
ORDER BY nazw kolumn:
SELECT IMIE, NAZWISKO
FROM KLIENCI
WHERE NAZWISKO LIKE ‘%SKI’
UNION
SELECT IMIE, NAZWISKO
FROM PRACOWNICY
WHERE NAZWISKO LIKE ‘%SKI’
ORDER BY 2 DESC;
Klauzula UNION ALL.
Różnica pomiędzy klauzulą UNION a UNION ALL polega na tym, że wynik łączenia zapytań klauzula UNION
ALL zawiera powtarzające się wiersze. Natomiast klauzula UNION ALL działa szybciej niż UNION. Zatem,
gdy łączymy klika wyników zapytania, i gdy jesteśmy pewni, że łączone wyniki nie zawierają duplikatów,
możemy używać klauzuli UNION ALL.
SELECT IMIE, NAZWISKO
FROM KLIENCI
WHERE NAZWISKO LIKE ‘%SKI’
UNION ALL
SELECT IMIE, NAZWISKO
FROM PRACOWNICY
WHERE NAZWISKO LIKE ‘%SKI’
ORDER BY 2 DESC;
W wyniku tego zapytania JAN KOWALSKI występuje dwa razy ponieważ UNION ALL nie usuwa duplikatów
Podsumowanie:
1. Wyniki zapytania SELECT z tą samą liczbą kolumn będących tego samego typu danych mogą być łączone
poprzez użycie klauzuli UNION.
2. Klauzula UNION sortuje dane wynikowe i usuwa duplikaty.
3. Klauzula UNION ALL działa szybciej niż UNION.
4. Klauzuli UNION ALL używamy, gdy jesteśmy pewni, że łączone wyniki nie zawierają duplikatów.
Dalsze przykłady dotyczą podzapytań. Pokażemy, jak konstruować podzapytania, jak je używać w klauzuli
HAVING oraz jak budować podzapytania ze słowami kluczowymi IN, ALL, ANY lub SOME.
Przypuśćmy, że musimy znaleźć pracowników, którzy otrzymują wynagrodzenie na kwotę większą niż wynosi
średnia. Musimy najpierw sprawdzić, jaka jest średnia pensja (dla każdego) pracownika:
SELECT AVG(P.PENSJA)
FROM PRACOWNICY P;
Teraz szukamy pracowników, którzy zarabiają powyżej średniej:
SELECT P.IMIE, P.NAZWISKO, P.DZIAL, P.STANOWISKO
FROM PRACOWNICY P
WHERE P.PENSJA > 1530;
Co prawda zrealizowaliśmy treść zadania, W DWÓCH KROKACH. Natomiast naszym celem jest realizacja
zadania JEDNYM POLECENIEM. Można to zrobić przy użyciu podzapytania:
SELECT P.IMIE, P.NAZWISKO, P.DZIAL, P.STANOWISKO
FROM PRACOWNICY P
WHERE P.PENSJA > (SELECT AVG(P.PENSJA)
FROM PRACOWNICY P);
Podzapytania z użyciem słów kluczowych IN oraz NOT IN.
Słowo kluczowe IN pozwala na zidentyfikowanie wszystkich elementów w zbiorze A, które występują w
zbiorze B. Dualnie, słowo kluczowe NOT IN pozwala na zidentyfikowanie wszystkich elementów w zbiorze
A, które nie występują w zbiorze B.
Zapytanie wyświetlające listę samochodów, których do tej pory nie wypożyczył żaden klient. Zapytanie wybiera
te samochody, które nie znajdują się w tabeli wypożyczenia, czyli te, które nie były do tej pory przedmiotem
wypożyczenia:
SELECT S.NR_SAMOCHODU, S.MARKA, S.TYP
FROM SAMOCHODY S
WHERE S.NR_SAMOCHODU
NOT IN
(SELECT W.NR_SAMOCHODU
FROM WYPOZYCZENIA W);
Podzapytania z użyciem słowa kluczowego ALL.
Poniższe podzapytanie przykładowe będzie wykonywane w trzech krokach. Najpierw wykonywane jest
podzapytanie, znajdujące średnią pensje w każdym dziale (działami). W drugim kroku, każda pensja pracownika
porównywana jest z listą średnich pensji. W końcu, wyświetleni zostaną pracownicy, których pensja jest wyższa
od wszystkich średnich pensji obliczonych w podzapytaniu:
SELECT P.IMIE, P.NAZWISKO, P.DZIAL, P.STANOWISKO, P.PENSJA
FROM PRACOWNICY P
WHERE
P.PENSJA > ALL (SELECT AVG(P.PENSJA)
FROM PRACOWNICY P
GROUP BY P.DZIAL);
Podzapytania z użyciem słowa kluczowego ANY lub SOME.
Poniższe zapytanie wykonywane jest w trzech krokach. Jako pierwsze jest wykonywane podzapytanie, które
znajduje średnia pensję w każdym dziale (działami). W drugim kroku, każda pensja pracownika porównywana
jest z lista średnich pensji. Ostatecznie, wyświetleni zostaną wszyscy pracownicy, których pensja jest wyższa od
najmniejszej średniej pensji obliczonej w podzapytaniu:
SELECT P.IMIE, P.NAZWISKO, P.DZIAL, P.STANOWISKO, P.PENSJA
FROM PRACOWNICY P
WHERE
P.PENSJA > ANY (SELECT AVG(P.PENSJA)
FROM PRACOWNICY P
GROUP BY P.DZIAL);
Słowo kluczowe SOME jest równoważne słowu ANY.
Podzapytania w klauzuli HAVING.
Chcemy znaleźć działy, w których średnia pensja pracowników jest wyższa od średniej pensji w firmie. Do
średnich pensji nie będą brani pod uwagę kierownicy działów. Gdybyśmy musieli wykonać to zadanie ręcznie,
to musielibyśmy wykonać trzy kroki. W pierwszym musielibyśmy znaleźć średnią pensje w firmie, nie biorąc
pod uwagę kierowników:
SELECT AVG(P.PENSJA)
FROM PRACOWNICY P
WHERE P.STANOWISKO <> ‘KIEROWNIK’;
W drugim obliczylibyśmy średnie pensje pracowników w poszczególnych działach, nie biorąc przy tym pod
uwagę kierowników:
SELECT P.DZIAL, AVG(P.PENSJA) AS SREDNIA_PENSJA
FROM PRACOWNICY P
WHERE P.STANOWISKO <> ‘KIEROWNIK’
GROUP BY P.DZIAL
ORDER BY 2;
Gdy używamy innego systemu DBMS niż InterBase, to ostatni wiersz bedzie wygladał nastepujaco:
ORDER BY SREDNIA_PENSJA;
W trzecim kroku musielibyśmy porównać wartości średnich pensji poszczególnych działów ze średnią pensją w
firmie.
Ostatecznie, wykonujemy to zadanie za pomocą pojedynczego zapytania z podzapytaniem w klauzuli HAVING.
SELECT P.DZIAL, AVG(P.PENSJA) AS SREDNIA_PENSJA
FROM PRACOWNICY P
WHERE P.STANOWISKO <> ‘KIEROWNIK’
GROUP BY P.DZIAL
HAVING AVG(P.PENSJA) > (SELECT AVG(P.PENSJA)
FROM PRACOWNICY P
WHERE P.STANOWISKO <> ‘KIEROWNIK’)
ORDER BY 2;
Podsumowanie:
1. Podzapytania musza być otoczone nawiasami.
2. Podzapytania nie mogą zawierać klauzuli UNION, UNION ALL, lub ORDER BY.
Utrzymywanie danych.
Obecnie pokażemy składnie poleceń do tworzenia tabel i widoków oraz pokażemy jak wprowadzać do tabeli
dane, jak te dane modyfikować, a także jak usuwać z tabel wiersze i jak usuwać całe tabele.
Tworzenie tabel. Utworzymy ćwiczeniową tabele wypełniona danymi. Tabele tworzy następujące polecenie.
CREATE TABLE KLIENCI_TEST (
NR_KLIENTA CHAR(8) NOT NULL,
IMIE VARCHAR(20) NOT NULL,
NAZWISKO VARCHAR(20) NOT NULL,
NR_KARTY_KREDYT CHAR(20) ,
ULICA VARCHAR(24) NOT NULL,
NUMER CHAR(8) NOT NULL,
MIASTO VARCHAR(24) NOT NULL,
KOD CHAR(6) NOT NULL,
NR_TELEFONU CHAR(16) ,
PRIMARY KEY (NR_KLIENTA) );
Definiując tabelę określamy jej nazwę – KLIENCI_TEST. Następnie określamy kolumny dla tej tabeli. Każda
kolumna musi posiadać unikatowa nazwę w obrębie tabeli oraz typ danych przechowywanych w kolumnie.
Dodatkowo przy definiowaniu kolumn można określić, czy dozwolone jest pozostawienie wartości pustych w tej
kolumnie. Jeśli nie, to dodajemy do definicji kolumny klauzule NOT NULL. W tabeli KLIENCI_TEST kolumna
NR_KARTY_KREDYT może być puste, co oznacza że nie każdy klient posiada kartę kredytową, a gdy nawet
taką kartę posiada, to nie musi nią realizować płatności. Słowo kluczowe PRIMARY KEY określa klucz główny
dla tabeli.
Tabele można przebudować dodając nowa kolumnę albo usuwając jakąś kolumnę istniejącą już w tabeli. Można
zmienić typ danych kolumny lub zmienić inne cechy tabeli oraz kolumn w niej zawartych. Do zmiany struktury
tabeli służy polecenie ALTER TABLE języka SQL.
Następujące polecenie ALTER TABLE dodaje dwie kolumny – FIRMA oraz NIP do tabeli KLIECI_TEST.
ALTER TABLE KLIENCI_TEST
ADD FIRMA VARCHAR(40),
ADD NIP CHAR(12);
W InterBase kolejne wiersze ze słowem ADD w powyższym należy oddzielić przecinkiem.
Poleceń ALTER TABLE używamy w celu poprawiania błędów definiowania tabel i schematu bazy danych.
Tworzenie widoków.
Dane zawarte w widoku nie musza być kompletnymi danymi jakiejś tabeli, a nawet nie musza pochodzić z
jednej tabeli. Widok, czyli perspektywa jest pewnym „oknem” na dane i może ono pokazywać dane z kilku
tabel. Widoki są tworzone głównie w celu ograniczenia dostępu do danych w tabelach bazy danych.
Do tworzenia widoków służy polecenie CREATE VIEW.
A oto przykład tworzenia widoku zawierającego dane klientów, którzy posiadają firmę.
CREATE VIEW KLIENCI_FIRMY AS
SELECT K.IMIE, K.NAZWISKO, K.FIRMA, K.NIP, K.MIASTO
FROM KLIENCI K
WHERE K.FIRMA IS NOT NULL;
Z widoku można wybierać dane, tak jak z tabeli.
SELECT *
FROM KLIENCI_FIRMY;
Tworzenie widoku, który ogranicza dane pracowników do wszystkich danych oprócz informacji na temat
dodatku i pensji:
CREATE VIEW PRACOWNICY_DANE_BEZ_PLAC AS
SELECT P.NR_PRACOWNIKA, P.IMIE, P. NAZWISKO,
P.DATA_ZATR, P.DZIAL, P.STANOWISKO,
P.NR_MIEJSCA, P.NR_TELEFONU
FROM PRACOWNICY P;
Dodawanie i usuwanie wierszy.
Aby dodać jeden lub więcej wierszy do istniejącej tabeli, należy posłużyć się poleceniem INSERT. Aby dodać
wiersz do tabeli KLIENCI_TEST musimy napisać i wykonać następujące polecenie SQL.
INSERT INTO KLIENCI_TEST
VALUES (‘00000031’, ‘MARIUSZ’, ‘DOLATA’, NULL, ‘KOCHANOWSKIEGO’, ‘3’,
‘WROCLAW’, ‘37-300’, ‘167-763-234’, ‘KWIATY’, ‘2224-444-224’);
Można dodać jeszcze kilka wierszy:
INSERT INTO KLIENCI_TEST
VALUES (‘00000032’, ‘TOMASZ’, ‘DOMAGALA’, ‘HX 145345678’, ‘ROZANA’, ‘4/9’,
‘WARSZAWA’, ‘01-900’, ‘46-744-431’, NULL, NULL);
INSERT INTO KLIENCI_TEST
VALUES (‘00000033’, ‘PAWEL’, ‘MALCZYKOWSKI’, ‘HF 14565661’, ‘SLONECZNA’,
‘9’, ‘WARSZAWA’, ‘01-900’, ‘16-742-114’, NULL, NULL);
INSERT INTO KLIENCI_TEST
VALUES (‘00000034’, ‘PIOTR’, ‘MUSZYNSKI’, ‘DD 72325221’, ‘SZYBOWCOWA’,
‘22A’, ‘WARSZAWA’, ‘01-200’, ‘144-188-415’, ‘FRYZJERSTWO’, ‘2343-112-345’);
Każde z tych poleceń wypełnia wartościami wszystkie kolumny tabeli.
Aby wstawić dane tylko do wybranych kolumn tabeli, należy je wyspecyfikować, a następnie podąć wartości.
INSERT INTO KLIENCI_TEST (NR_KLIENTA, IMIE, NAZWISKO, ULICA, NUMER, MIASTO,
KOD)
VALUES (‘00000036’, ‘MAGDALENA’, ‘BRZOZA’,‘ALEJE LIPOWE’, ‘4/3’,
‘SWIDNICA’, ‘58-100’);
Aby usunąć wiersze z tabeli, używamy polecenia DELETE FROM:
DELETE FROM KLIENCI_TEST WHERE FIRMA IS NOT NULL;
Polecenie DELETE FROM bez klauzuli WHERE usuwa wszystkie wiersze z tabeli.
DELETE FROM KLIENCI_TEST;
Zmiana danych w tabeli.
Polecenie UPDATE zmienia wartości we wskazanych kolumnach tabeli dla jednego lub więcej wierszy.
Najpierw sprawdzamy, jaki obecnie sprzedawcy maja dodatek:
SELECT *
FROM PRACOWNICY
WHERE STANOWISKO = ‘SPRZEDAWCA’;
Następujące polecenie UPDATE zmienia kwotę dodatku pracownika zatrudnionego na stanowisku sprzedawcy o
50 zł:
UPDATE PRACOWNICY
SET DODATEK = DODATEK + 50
WHERE STANOWISKO = ‘SPRZEDAWCA’;
Sprawdzamy, czy wartości dodatku dla sprzedawców zostały zmienione:
SELECT *
FROM PRACOWNICY
WHERE STANOWISKO = ‘SPRZEDAWCA’;
Jeżeli zmieniamy wartości więcej niż jednej kolumny, kolumny musza być oddzielone przecinkami.
A oto polecenie zwiększające dodatek dla kierowników o 30 zł oraz zwiększające pensje o 10%.
UPDATE PRACOWNICY
SET DODATEK = DODATEK + 30,
PENSJA = PENSJA + (PENSJA * 10)/100
WHERE STANOWISKO = ‘KIEROWNIK’;
Usuwanie tabel.
Aby usunąć tabele, stosujemy polecenie DROP TABLE. Jeśli transakcja na tabeli trwa, to trzeba ja wcześniej
zatwierdzić (COMMIT) lub wycofać (ROLLBACK).
DROP TABLE KLIENCI_TEST;
Polecenie usuwające tabele usuwa jednocześnie wszystkie dane zawarte w tabeli oraz wszystkie widoki
czerpiące dane z usuwanej tabeli.
Podsumowanie:
1. Usuniecie tabeli powoduje usuniecie danych i widoków związanych z usuwaną tabelą.
2. Można określić wiersze, które maja być usunięte lub zmienione poprzez zamieszczenie odpowiedniego
warunku w klauzuli WHERE.
3. Opuszczenie klauzuli WHERE w poleceniach UPDATE lub DELETE powoduje, że wszystkie wiersze
zostaną zmienione lub usunięte.
Ograniczenia i integralność referencyjna.
Ograniczenia, integralność danych i integralność referencyjna składają się na bezpieczeństwo i jakość
gromadzonych w bazie danych.
Ograniczenia.
Można zdefiniować ograniczenie sprawdzające poprawność wprowadzanych danych do tabeli poprzez
określenie warunku sprawdzającego CHECK.
Zmienimy strukturę tabeli PRACOWNICY przez dodanie ograniczenia zapobiegającego wprowadzeniu kwoty
dodatku większej od kwoty pensji.
ALTER TABLE PRACOWNICY
ADD CHECK (PENSJA > DODATEK);
Jeśli teraz wpiszemy polecenie dodające wiersz do tabeli PRACOWNICY, który będzie zawierał w kolumnie
DODATEK wartość większą niż w kolumnie PENSJA, baza wygeneruje komunikat o błędzie, mówiący o
naruszeniu ograniczenia sprawdzającego CHECK. Ważne jest, że zmiany definicji tabeli powinny być wykonane
w zasadzie na etapie definiowania schematu, przed wprowadzeniem jakichkolwiek danych do tabeli, a być może
do bazy.
Integralność danych – klucz główny.
Jak wiemy, każda tabela bazy danych musi zawierać klucz główny. Klucz główny to kolumna lub grupa kolumn,
która w sposób jednoznaczny identyfikuje wiersz w tabeli. Przykładowo, dla tabeli zawierającej dane o
pracownikach kluczem głównym może być kolumna o nazwie NR_PRACOWNIKA, która jednoznacznie
określa danego pracownika. Kluczem głównym może być NR_TELEFONU w tabeli przechowującej dane
abonentów operatora telefonicznego. Przykładem klucza głównego z wielu kolumn może być klucz z kolumn
NUMER oraz ROK w tabeli przechowującej dane o wystawionych fakturach, gdzie kolumna NUMER określa
numer faktury, a kolumna ROK określa rok wystawienia. Wartości z tych kolumn wzięte razem są różne w
każdym wierszu.
Dla tabeli PRACOWNICY kluczem głównym może być kolumna NR_PRACOWNIKA. Ustalenie klucza
głównego
(PRIMARY KEY) odbywa się podczas tworzenia tabeli.
CREATE TABLE PRACOWNICY_TEST(
NR_PRACOWNIKA CHAR(4) NOT NULL,
IMIE VARCHAR(20) NOT NULL,
NAZWISKO VARCHAR(20) NOT NULL,
DATA_ZATR DATE NOT NULL,
DZIAL VARCHAR(20) NOT NULL,
STANOWISKO VARCHAR(20) NOT NULL,
PENSJA DECIMAL(8,2) ,
DODATEK DECIMAL(8,2) ,
NR_MIEJSCA CHAR(6) NOT NULL,
NR_TELEFONU CHAR(16) ,
PRIMARY KEY (NR_PRACOWNIKA));
Jak wiemy, klucz zapobiega wstawieniu dwóch identycznych wierszy (musza się różnić przynajmniej wartością
klucza). Próba wstawienia identycznego wiersza spowoduje powstanie błędu sygnalizowanego odpowiednim
komunikatem.
Integralność referencyjna – klucz obcy.
Kasujemy bazę danych poleceniem DROP DATABASE WYPAUT;. Zamykamy query analyzer.
Wylogowujemy sie z serwera lokalnego Local Server. Zamykamy IBConsole. Na wszelki wypadek możemy
sprawdzić, czy został usunięty plik bazy danych WYPAUT w folderze ‘bin’ oprogramowania Interbase w
‘Program Files’.
Tworzymy baze danych powtórnie, ale bez danych. Najpierw tworzymy pojemnik WYPAUT za pomocą
opcji Create Database. (to może potrwać kilka chwil), potem schemat za pomocą skryptów pozbawionych
poleceń INSERT INTO.
Tworzymy też tabele PRACOWNICY_TEST:
CREATE TABLE PRACOWNICY_TEST(
NR_PRACOWNIKA CHAR(4) NOT NULL,
IMIE VARCHAR(20) NOT NULL,
NAZWISKO VARCHAR(20) NOT NULL,
DATA_ZATR DATE NOT NULL,
DZIAL VARCHAR(20) NOT NULL,
STANOWISKO VARCHAR(20) NOT NULL,
PENSJA DECIMAL(8,2) ,
DODATEK DECIMAL(8,2) ,
NR_MIEJSCA CHAR(6) NOT NULL,
NR_TELEFONU CHAR(16) ,
PRIMARY KEY (NR_PRACOWNIKA));
Jak wiemy, klucz obcy to jedna lub więcej kolumn odwołujących się do kolumny lub kolumn klucza głównego
innej tabeli. Klucze obce są wykorzystywane do integralności referencyjnej w bazie danych. Tworząc klucz obcy
definiujemy związek miedzy tabela klucza obcego i tabela klucza głównego. Związek taki powstaje podczas
złączania kolumn takich samych typów danych z każdej tabeli. Złączanie tabel przez odpowiednie kolumny
chroni dane z tabeli klucza obcego przed „osieroceniem”, jakie mogłoby nastąpić w wyniku usunięcia
odpowiadających im danych z tabeli klucza głównego. Definiowanie kluczy obcych jest, zatem sposobem
łączenia danych przechowywanych w różnych tabelach bazy danych.
Przykładowo, jeśli w tabeli PRACOWNICY kluczem obcym jest kolumna NR_MIEJSCA, to kolumna czerpie
wartości z tabeli MIEJSCA. Gdy odczytamy NR_MIEJSCA z tabeli PRACOWNICY, to możemy odwołać się
do tabeli MIEJSCA i odczytać z niej pełny adres miejsca pracy pracownika. Tabela PRACOWNICY z kluczem
obcym jest złączona z tabelą MIEJSCA z kluczem głównym, poprzez referencje do krotek z identycznymi
wartościami klucza głównego jak te wartości, które ma klucz obcy. Związek klucza obcego chroni wiersze z
tabeli PRACOWNICY przed osieroceniem na wypadek usunięcia jakiegokolwiek wiersza z tabeli MIEJSCA.
Aby zapewnić taką ochronę, musimy zdefiniować klucze obce we wszystkich tabelach, które odwołują się do
innych tabel.
Taki związek występuje w naszych przykładowych tabelach PRACOWNICY oraz MIEJSCA.
ALTER TABLE WYPOZYCZENIA
ADD FOREIGN KEY (NR_PRACOW_WYP)
REFERENCES PRACOWNICY_TEST (NR_PRACOWNIKA) ON DELETE CASCADE;
To polecenie ustanawia klucz obcy w tabeli WYPOZYCZENIA na kolumnie NR_PRACOWNIKA_WYP.
Przeglądając dalej to polecenie można się dowiedzieć, że kolumna ta odwołuje się do kolumny
NR_PRACOWNIKA. Słowo kluczowe ON DELETE CASCADE mówi, że usuwanie wiersza z tabeli
PRACOWNICY_TEST pociąga za sobą usuniecie wiersza do niego się odwołującego (ściślej, wiersza
partnerskiego względem referencji) w tabeli WYPOZYCZENIA.
A oto jak sprawdzić, że krotki zostaną wykasowane kaskadowo.
Najpierw wprowadzamy krotkę „na stronę 1”:
INSERT INTO PRACOWNICY_TEST
VALUES (‘0020’, ‘WOJTEK’, ‘WOJTKOWSKI’, ‘1998-04-01’, ‘OBSLUGA KLIENTA’,
‘SPRZEDAWCA’, 1200, 100, ‘000004’, ‘457-531-143’);
Następnie wprowadzamy krotkę „na stronę M”:
INSERT INTO WYPOZYCZENIA
VALUES (‘00000055’, ‘00000010’, ‘000004’, ‘0020’, NULL, ‘000002’, NULL,
‘200002-09’, NULL, 200, 100);
Następnie usuwamy krotkę „po stronie 1”:
DELETE FROM PRACOWNICY_TEST
WHERE NAZWISKO = ‘WOJTKOWSKI’;
Krotki zostały (kaskadowo) usunięte! Zarówno ta „po stronie 1” w tabeli PRACOWNICY_TEST, jak i ta „po
stronie M” w tabeli WYPOZYCZENIA. Przede wszystkim krotka z tabeli PRACOWNICY_TEST („ze strony
1”), a kaskadowo również krotki z nią powiązane referencyjnie „po stronie M” z tabeli WYPOZYCZENIA.
Inaczej przebiega kasowanie krotek, gdy usuwamy krotkę „po stronie M” w tabeli WYPOZYCZENIA.
A oto jak sprawdzić, że w tym przypadku zostaną wykasowane krotki jedynie z tabeli WYPOZYCZENIA „po
stronie M”:
Najpierw wprowadzamy krotkę „na stronę 1”:
INSERT INTO PRACOWNICY_TEST
VALUES (‘0020’, ‘WOJTEK’, ‘WOJTKOWSKI’, ‘1998-04-01’, ‘OBSLUGA KLIENTA’,
‘SPRZEDAWCA’, 1200, 100, ‘000004’, ‘457-531-143’);
Następnie wprowadzamy krotkę „na stronę M”:
INSERT INTO WYPOZYCZENIA
VALUES (‘00000055’, ‘00000010’, ‘000004’, ‘0020’, NULL, ‘000002’, NULL,
‘200002-09’, NULL, 200, 100);
Następnie usuwamy krotkę „po stronie M”:
DELETE FROM WYPOZYCZENIA
WHERE NR_PRACOW_WYP = ‘0020’;
Zostały usunięte jedynie krotki z tabeli WYPOZYCZENIA „po stronie M”!
Obecnie zbadamy nieco inną definicję integralności referencyjnej. Jest ona oparta na definicji klucza obcego za
pomocą polecenia ALTER TABLE WYPOZYCZENIA ... ON DELETE NO ACTION; Znowu trzeba
skasować bazę danych, utworzyć ja powtórnie, ale bez danych. Utworzyć tabele PRACOWNICY_TEST i
wykonać podobne akcje, co przedtem.
CREATE TABLE PRACOWNICY_TEST(
NR_PRACOWNIKA CHAR(4) NOT NULL,
IMIE VARCHAR(20) NOT NULL,
NAZWISKO VARCHAR(20) NOT NULL,
DATA_ZATR DATE NOT NULL,
DZIAL VARCHAR(20) NOT NULL,
STANOWISKO VARCHAR(20) NOT NULL,
PENSJA DECIMAL(8,2) ,
DODATEK DECIMAL(8,2) ,
NR_MIEJSCA CHAR(6) NOT NULL,
NR_TELEFONU CHAR(16) ,
PRIMARY KEY (NR_PRACOWNIKA));
Oraz ze skryptu utworzyć tabelę WYPOZYCZENIA z pominięciem poleceń INSERT.
Po utworzeniu tabel definiujemy w tabeli WYPOZYCZENIA klucz obcy w następujący sposób:
UWAGA: NO ACTION jest w systemie InterBase odpowiednikiem słowa RESTRICT używanego w
definicjach więzów referencyjnych klucza obcego w innych systemach DBMS.
ALTER TABLE WYPOZYCZENIA
ADD FOREIGN KEY (NR_PRACOW_WYP)
REFERENCES PRACOWNICY_TEST (NR_PRACOWNIKA) ON DELETE NO ACTION;
Najpierw wprowadzamy krotkę „na stronę 1”:
INSERT INTO PRACOWNICY_TEST
VALUES (‘0020’, ‘WOJTEK’, ‘WOJTKOWSKI’, ‘1998-04-01’, ‘OBSLUGA KLIENTA’,
‘SPRZEDAWCA’, 1200, 100, ‘000004’, ‘457-531-143’);
Następnie wprowadzamy krotkę „na stronę M”:
INSERT INTO WYPOZYCZENIA
VALUES (‘00000055’, ‘00000010’, ‘000004’, ‘0020’, NULL, ‘000002’, NULL,
‘2000-02-09’, NULL, 200, 100);
Następnie próbujemy usunąć krotkę „po stronie 1”:
DELETE FROM PRACOWNICY_TEST
WHERE NAZWISKO = ‘WOJTKOWSKI’;
Krotki wcale nie zostaną usunięte! Ani „po stronie 1”, ani „po stronie M”.
Próbujemy, zatem usunąć krotkę „po stronie M”:
DELETE FROM WYPOZYCZENIA
WHERE NR_PRACOW_WYP = ‘0020’;
Zostały usuniete jedynie krotki z tabeli WYPOZYCZENIA „po stronie M”! W tabeli „po stronie 1” w tabeli
PRACOWNICY_TEST krotka powiązana referencyjnie pozostała.
A oto opisy wszystkich możliwych akcji, jakie zostaną zainicjowane w chwili usuwania wiersza w tabeli
zależnej.
Akcja
RESTRICT
(lub dla InterBase)
NO ACTION
CASCADE
SET NULL
Opis
Ograniczone usuwanie, które mówi, że dopóty istnieją w tabeli WYPOZYCZENIA
wiersze odwołujące się do usuwanego adresu w jakimś wierszu tabeli
PRACOWNICY_TEST, wiersza z tabeli PRACOWNICY_TEST nie można usunąć.
Należy najpierw usunąć wszystkie referencyjnie powiązane krotki z tabeli zależnej
WYPOZYCZENIA.
Kaskadowe usuwanie mówi, że gdy usuwamy wiersze z tabeli PRACOWNICY_TEST,
to są jednocześnie usuwane wszystkie wiersze z danymi o wypożyczeniach z tabeli
zależnej WYPOZYCZENIA o wypożyczeniach dokonanych przez usuwanego
pracownika.
Wstaw wartość NULL. Mówi, że możemy usunąć dane o pracowniku w tabeli
PRACOWNICY_TEST. Wtedy w tabeli zależnej WYPOZYCZENIA pozostaną krotki
osierocone z wypożyczeniami realizowanymi przez pracowników, którzy te
wypożyczenia realizowali, a którzy to pracownicy zostali skasowani. Naturalnie
usuniecie krotek z tabeli zależnej WYPOZYCZENIA będzie zawsze możliwe.
Podsumowanie:
1. Możliwe jest zdefiniowanie ograniczenia sprawdzającego poprawność wpisywanych do tabeli danych poprzez
określenie warunku sprawdzającego CHECK.
2. Integralność danych w tabeli zachowuje się dzięki kluczom głównym.
3. Klucze obce służą do utrzymania integralności referencyjnej.

Podobne dokumenty