Professional Documents
Culture Documents
Bazy Danych I PostgreSQL. Od Podstaw
Bazy Danych I PostgreSQL. Od Podstaw
Bazy Danych I PostgreSQL. Od Podstaw
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
"
"
"
"
"
"
"
"
Podzikowania ......................................................................................................................................15
Wstp.....................................................................................................................................................17
Jak wymawia PostgreSQL..................................................................................... 17
Co jest treci tej ksiki?........................................................................................ 17
Stosowane konwencje.............................................................................................. 19
Pobranie kodu rdowego ........................................................................................ 20
Rozdzia 3. Instalacja........................................................................................................................... 63
Instalowa czy uaktualnia?...................................................................................... 64
Instalacja PostgreSQL z pakietw binarnych systemu Linux ......................................... 64
Anatomia instalacji PostgreSQL ...................................................................... 66
Instalacja PostgreSQL z kodu rdowego .................................................................. 69
Uruchamianie PostgreSQL.............................................................................. 72
Tworzenie bazy danych................................................................................... 76
Tworzenie tabel ............................................................................................. 78
Usuwanie tabel ............................................................................................. 79
Wypenianie tabel danymi............................................................................... 80
Zatrzymywanie PostgreSQL............................................................................. 82
Instalacja PostgreSQL w Windows ............................................................................. 83
Cygwin rodowisko UNIX w systemie Windows............................................. 83
Usugi IPC dla Windows ................................................................................. 87
PostgreSQL dla Cygwin .................................................................................. 88
Kompilacja PostgreSQL w Windows................................................................. 88
Konfiguracja PostgreSQL dla Windows ............................................................ 89
Automatyczne uruchamianie PostgreSQL ......................................................... 90
Spis tre+ci
Spis tre+ci
Spis tre+ci
10
Spis tre+ci
11
12
Spis tre+ci
13
PL/Python........................................................................................................ 586
Psql................................................................................................................. 586
Libpq ............................................................................................................... 586
JDBC ............................................................................................................... 587
ODBC .............................................................................................................. 588
ECPG............................................................................................................... 588
Rne interfejsy................................................................................................ 589
Kompilacja i instalacja ...................................................................................... 589
Kod rdowy.................................................................................................... 590
Contrib ............................................................................................................ 590
Skorowidz ..........................................................................................................................................593
funkcje agregacji;
190
zapytania podrzdne;
powizania zewntrzne.
COUNT
Rozpoczniemy od funkcji , ktra jak wida z przedstawionej powyej listy
ma dwie postacie. Funkcja oblicza liczb wierszy w tabeli. Peni ona rol specjalnej nazwy kolumny w instrukcji . W tych instrukcjach , ktre wykorzystuj dowolne z funkcji agregacji, mona stosowa dwie opcjonalne klauzule: ' ()
oraz * . Skadnia jest wwczas nastpujca:
!"# $!
%&
'()*%#+,-&$.$!./011
Nowa, opcjonalna klauzula ' () jest dodatkowym warunkiem, z ktrego mona korzysta w instrukcjach . Zazwyczaj korzysta si z niej w przypadku stosowania
funkcji agregacji. Mona j take wykorzysta jako funkcj podobn do + (), ale
dziaajc z kolumn, na podstawie ktrej zostaa wyliczona warto funkcji agregacji.
Opcjonalna klauzula * pozwala na wybr okrelonych wierszy dla pewnych warunkw funkcji , jeeli wykorzystalimy ju klauzul ' ().
191
Brzmi to bardzo tajemniczo, ale w praktyce jest dosy proste. Sprbujmy skorzysta
z bardzo prostej instrukcji , aby mie obraz jej dziaania. Wkrtce poznamy
take dziaanie klauzuli ' ().
lub, w bardziej wydajny sposb, zapisa instrukcj SQL, ktra daje w wyniku mniejsz
ilo danych:
/!$
/!$"# 23(.435
Gdybymy chcieli policzy wszystkich klientw, moglibymy po prostu pomin klauzul 0*:
66!27
#
/
88888888
:;
66!27
Jak to dziaa?
Funkcja umoliwia uzyskanie liczby obiektw, a nie obiektw samych w sobie. W wikszoci wypadkw jest to znacznie bardziej wydajne ni wybieranie danych,
z dwch powodw:
192
nie trzeba pobiera z bazy danych informacji, ktre nie s nam potrzebne;
Nigdy nie naley wybiera danych, jeeli potrzebujemy tylko liczby wierszy.
GROUP BY a COUNT(*)
Odpowied na zapytanie pokazane w poprzednim podrozdziale nie zawsze speni nasze
oczekiwania. Przypumy, e chcielibymy wiedzie, ilu klientw mieszka w kadym
miecie. Moglibymy dowiedzie si tego wybierajc list rnych miast, a nastpnie
wyliczajc, ilu klientw mieszka w kadym z nich. Jest to jednak proceduralny i raczej
mudny sposb rozwizania problemu. Czy nie byoby lepiej zastosowa sposb deklaracyjny, formuujc zapytanie bezporednio w SQL? Moglibymy pokusi si o wyprbowanie nastpujcej instrukcji:
<
/!$5
Jest to rozsdna prba, zwaywszy na to, co wiemy do tej pory, ale PostgreSQL wywietli komunikat o bdzie, poniewa nie jest to poprawna skadnia SQL. Aby rozwiza ten problem, potrzebujemy dodatkowej klauzuli ' ().
Klauzula ' () informuje PostgreSQL, e funkcja agregacji powinna obliczy wynik
i wyzerowa si za kadym razem, kiedy okrelona kolumna lub kolumny zmieni warto. Jest ona bardzo prosta w uyciu. Wystarczy doda zapis ' ()
do instrukcji z funkcj , a PostgreSQL poinformuje nas, ile wierszy
o okrelonej wartoci kolumny znajduje si w tabeli.
Wyprbuj to GROUP BY
Sprbujmy odpowiedzie na pytanie, ilu klientw mieszka w kadym miecie?
Etap pierwszy polega na napisaniu instrukcji , ktra zawiera funkcj
oraz nazw kolumny, dokadnie tak, jak prbowalimy odgadn:
<
/!$5
Nastpnie naley doda klauzul ' (), aby poinformowa PostgreSQL, e powinien
obliczy wynik i wyzerowa licznik za kadym razem, kiedy zmieni si miasto. Mona
to zrobi za pomoc nastpujcego zapytania:
<
/!$&
'()5
193
:=#.4
:=#
:=
:=
?=/!
:=
4!4
:=
@ $.!
:= A!
:="!
:="!$ *
:=)!A!
:?$
66!27
Jak widzimy, uzyskalimy przejrzyst list miast wraz z liczb klientw w kadym
z nich.
Jak to dziaa?
PostgreSQL porzdkuje wynik wedug kolumn wymienionych w klauzuli ' (), nastpnie oblicza liczb wierszy i za kadym razem, kiedy zmienia si miasto, zapisuje
wiersz wyniku, po czym zeruje licznik. Zgodzimy si, e jest to o wiele atwiejsze ni
pisanie kodu procedury z ptl dla kadego miasta.
Jeeli zachodzi taka potrzeba, sposb ten mona zastosowa do wicej ni jednej kolumny, pod warunkiem, e wszystkie kolumny, ktre wybrano, s take wymienione
w klauzuli ' (). Przypumy, e interesoway nas dwie informacje. Po pierwsze, ilu
klientw mieszka w kadym miecie, po drugie, ile rnych nazwisk maj ci klienci.
Moemy po prostu doda kolumn . zarwno do czci , jak ' ():
66!27
$("$
%&'$("#
/=!=
8888888>888888888>88888888888
:=B!=(.4
?=!=(.4
:=!=#.4
:=#/=#
:=!=
:=#=
?=4!=/!
:=!=
4!4
:=#!*=
@ $.!
:=#$= A!
:=
3!="!
:=!="!$ *
:=4!=)!A!
:9$
66!27
Zwrmy uwag, e wynik jest posortowany najpierw wedug miasta, a nastpnie wedug nazwiska, poniewa w tej kolejnoci (-2 .) wymieniono kolumny w klauzuli ' () oraz na to, e obecnie Bingham znajduje si na licie dwa razy, poniewa
mieszkaj w nim klienci o dwch rnych nazwiskach,
.# oraz -.#.
194
HAVING a COUNT(*)
Ostatni opcjonaln czci instrukcji jest klauzula * . Czsto jest ona mylca dla
pocztkujcych programistw piszcych w jzyku SQL, ale w rzeczywistoci nie jest
trudna w uyciu. Naley po prostu pamita, e * jest rodzajem klauzuli 0* dla
funkcji agregacji. Klauzul * wykorzystujemy w celu ograniczenia liczby zwracanych wierszy, gdzie
Uycie funkcji agregacji w klauzuli "# nie jest poprawne. S% one poprawne tylko
wewn%trz klauzuli #+,-&.
okrelona funkcja agregacji, na przykad , ma warto . Uywamy jej
w dokadnie taki sam sposb, jak klauzuli 0*, w celu ograniczenia liczby wierszy na
podstawie wartoci kolumny.
Spjrzmy na przykad, ktry powinien sprawi, e zagadnienie to stanie si atwe
i przyjemne. Przypumy, e chcemy zna wszystkie miasta, w ktrych mamy wicej
ni jednego klienta. Moglibymy wwczas uy funkcji , a nastpnie odszuka
na licie interesujce nas miasta. Nie jest to jednak rozwizanie sensowne w sytuacji,
gdy mamy tysice miast. Zamiast tego skorzystamy z klauzuli * w celu ograniczenia wyniku do tych wierszy, gdzie warto funkcji jest wiksza ni jeden. Zrobimy to w nastpujcy sposb:
66!27
$
66!87%&')*+ %
,-#
/=
8888888>8888888888
9=(.4
?=/!
?$
66!27
Zauwamy, e w dalszym cigu musimy zapisa klauzul ' () i musi ona wystpowa przed klauzul * . Teraz, kiedy znamy podstawy funkcji , klauzuli
' () oraz * , sprbujmy wykorzysta je wszystkie w wikszym przykadzie.
Wyprbuj to HAVING
Przypumy, e mylimy o opracowaniu harmonogramu dostaw i chcemy zna nazwiska wszystkich klientw i miasta, skd pochodz, oprcz klientw z Lincoln (by moe
jest to nasze miasto). Interesuj nas tylko te miasta, w ktrych mamy wicej ni jednego
klienta.
Nie jest to takie trudne, jak mogoby si wydawa; musimy po prostu stopniowo stworzy nasze rozwizanie. Jest to zazwyczaj dobre podejcie dla instrukcji SQL. Jeeli co
wyglda na zbyt trudne, naley rozpocz od rozwizania czego prostszego, ale podobnego, a nastpnie rozszerzy rozwizanie do momentu, a uda si rozwiza problem
bardziej skomplikowany. Tak wic naley rozpozna problem, podzieli go na mniejsze
czci, a nastpnie rozwiza kad z nich.
195
Zacznijmy od wybrania danych, a nie ich liczenia. Dane uporzdkujemy wedug miasta,
aby mona byo atwiej zorientowa si, o co chodzi:
66!27("$
.,(#
!=
888888888>88888888888
!=#.4
!=
4!=/!
4!=)!A!
!=
4!4
4!=/!
!=(.4
!=(.4
#/=#
#$= A!
B!=(.4
!="!$ *
#!*=
@ $.!
3!="!
#=
:;$
66!27
Moemy teraz odnale odpowied samodzielnie przegldajc dane, ale jestemy zaledwie o krok od waciwego wyniku. Wystarczy doda klauzul * , a zostan wybrane wiersze, gdzie warto funkcji jest wiksza ni 1:
196
Jak to dziaa?
Rozwizalimy nasz problem w trzech etapach:
n
nastpnie dodalimy sowa kluczowe oraz ' () w celu obliczenia
liczby unikalnych kombinacji nazwiska i miasta (. oraz -);
Przy takim podejciu istnieje jednak pewien problem. Gdybymy mieli do czynienia
z baz danych klientw, ktra zawieraaby tysice wierszy, lista klientw przewijaaby
si nam bardzo dugo w czasie opracowywania naszego zapytania. Dla naszej prostej
bazy danych nie stanowio to problemu, ale dla duej bazy danych takie interaktywne
podejcie w opracowywaniu zapytania ma pewne wady. Na szczcie zazwyczaj atwo
opracowa zapytania na prbce danych, z wykorzystaniem klucza podstawowego. Gdybymy do wszystkich zapyta dodali warunek 0* ,#-./1&345, pracowalibymy
z prbk pierwszych 50 klientw w bazie.
Kiedy ju bdziemy pewni, e zapytanie jest poprawne, moemy po prostu usun klauzul 0* i wykona nasze rozwizanie dla caej tabeli. Oczywicie musimy by pewni,
e zastosowana prbka danych, wykorzystana w celu przetestowania naszej instrukcji
SQL, jest reprezentantem caoci zbioru danych oraz musimy mie na uwadze, e
mniejsze prbki mog nie w peni testowa nasz instrukcj SQL.
COUNT(nazwa_kolumny)
Pewn odmian funkcji jest uycie nazwy kolumny zamiast znaku 66. Rnica polega na tym, e funkcja oblicza ilo wierszy w tabeli,
w ktrych okrelona kolumna ma warto rn od .
Przypumy, e do naszej kolumny ,#-./ dodalimy pewne dane o nowych klientach, za numery telefonw zawarte w tych danych maj warto :
- -
/!$!<C!<!<$!!<<6/!
,+
3$3<3&A3<3*43<3?9#$!!3<33<3DD#-35
197
Sprawdmy, ilu jest klientw, dla ktrych nie znamy numerw telefonw:
66!27/0
1!+ #
/!$
88888888888888
:J
:E
:H
9$
66!27
Widzimy, e mamy trzech takich klientw. Sprawdmy teraz, ilu wszystkich klientw
jest w bazie danych:
66!27
#
/
8888888
:H
:$
66!27
Mamy w sumie 19 klientw. Tak wic, jeeli obliczymy liczb klientw, ktrych warto numeru telefonu jest rna od , prawdopodobnie otrzymamy 16:
66!27
1!
#
/
8888888
:J
:$
66!27
Jest to jedyna rnica pomidzy a . Odmiana funkcji
z nazw kolumny oblicza wiersze, w ktrych kolumna o okrelonej nazwie ma warto
rn ni , posta funkcji ze znakiem 66 oblicza za liczb wszystkich wierszy.
Pod kadym innym wzgldem, jak choby w przypadku uycia ' () oraz * ,
dziaa dokadnie tak samo jak .
Funkcja MIN()
Teraz, kiedy znamy funkcj i poznalimy zasady obowizujce dla funkcji agregacji, moemy zastosowa t sam logik do wszystkich pozostaych funkcji agregacji.
198
W rzeczywistoci warto ta wynosia zero. Zwrmy uwag, co si stanie, jeeli zastosujemy t sam funkcj z kolumn "7., o ktrej wiemy, e istniej w niej wartoci :
66!27+
1!
#
8888888
K:KF;JD
:$
66!27
Moglibymy si spodziewa, e wynik bdzie teraz mia warto lub bdzie pustym cigiem znakw. Biorc jednak pod uwag, e z reguy oznacza nieznany,
funkcja
ignoruje t warto. Ignorowanie wartoci jest cech wszystkich
funkcji agregacji oprcz . To, czy posiadanie informacji o najmniejszym numerze telefonu ma jakiekolwiek znaczenie, jest oczywicie odrbn kwesti.
Funkcja MAX()
Nie jest zaskoczeniem, e funkcja
jest podobna do
, ale dziaa w odwrotnym
kierunku.
Jak mona si spodziewa,
jako parametr przyjmuje nazw kolumny i zwraca
maksymaln warto znalezion w tej kolumnie.
Oto kilka przykadw.
Poszukajmy najwikszej opaty transportowej, jak naoylimy na zamwienie:
66!27
+M466.
$!$C5
@
88888888
199
9LHH
:$
66!27
To w zasadzie wszystko, co naley wiedzie o funkcji
, z wyjtkiem tego, e mona z ni uywa klauzul ' () oraz * , dokadnie tak, jak w przypadku funkcji
.
Funkcja SUM()
Funkcja
przyjmuje jako parametr nazw kolumny o typie numerycznym i zwraca
sum wartoci dla tej kolumny. Tak jak funkcje
oraz
, funkcja
ignoruje wartoci typu :
66!27
!11
02#
8888888
HLHD
:$
66!27
Funkcja AVG()
Ostatni opisan funkcj agregacji jest , jako parametr przyjmujca rwnie nazw
kolumny i zwracajca warto redni. Podobnie jak funkcja
, take ignoruje
200
Omwimy teraz sposb poczenia kilku instrukcji dla zapewnienia wikszych
moliwoci wyszukiwania.
Pamitamy z poprzedniego rozdziau tabel -,#-, ktr wykorzystalimy jako tabel
tymczasow w celu adowania danych do tabeli ,#-./. Przypumy, e w okresie
czasu pomidzy adowaniem informacji o nowych klientach do tabeli -,#- a wyczyszczeniem tabeli i zaadowaniem danych do rzeczywistej tabeli ,#-./, pojawio si
pytanie o list wszystkich miast, w ktrych mamy klientw, z uwzgldnieniem nowych
informacji. Moemy susznie zauway, e poniewa jeszcze nie zaadowalimy danych o klientach do gwnej tabeli i nie wyczycilimy danych nie moemy by
pewni dokadnoci nowych danych. Tak wic adna lista miast czca obie listy rwnie nie bdzie dokadna. Czasami jednak nie jest to wane. By moe potrzebna bya
tylko oglna informacja o geograficznym rozproszeniu klientw, a nie dokadne dane.
Moemy rozwiza ten problem poprzez wybranie miasta (-) z tabeli ,#-./ i zapisanie wyniku, a nastpnie wybranie miasta (-) z tabeli -,#-, ponowne zapisanie
oraz poczenie obu list. Wyglda to raczej nieelegancko, poniewa mamy dwie tabele,
obie zawierajce list miast.
Czy nie ma sposobu, aby inaczej poczy listy? Jak mona wywnioskowa z tytuu tego
podrozdziau, istnieje taki sposb i nazywa si powizaniem typu . Powizania te
nie s zbyt popularne, ale w pewnych okolicznociach s waciwym rodkiem do rozwizania problemu i s ponadto bardzo atwe w uyciu.
201
Sprbujmy ponownie umieci pewne dane w tabeli -,#-, aby miaa nastpujc zawarto:
66!27
#
!=C!=!=$!!==6/!=64!
8888888>888888888>888888888>8888888888888888>8888888888>888888888888>8888888888
$='!!$=($!*=D?!=N!*!=NF:?#I=
$=N!A=$!*=F9&!"*=
/=
-?DG=DEJ9F;F
$=($="!$=?:$!=
/=
-DJ&=DEJD?F;
$=/="4!*=9$/"*="!="9F&I=F9;J;F9
F$
66!27
Kada z tych instrukcji daje w wyniku list miast. Aby je poczy, zastosujemy operator :
/-
/!$5
202
Jak to dziaa?
PostgreSQL stworzy list miast z obu tabel i poczy je w pojedyncz list. Zauwamy,
e wszystkie duplikaty zostay usunite. Gdybymy chcieli uzyska list wszystkich
miast wcznie z duplikatami, zapisalibymy zamiast .
Waciwo czenia instrukcji nie ogranicza si do pojedynczej kolumny, moglibymy poczy take list miast i kodw pocztowych:
<6/!
/-
<6/!
/!$5
Spowodowaoby to utworzenie listy zoonej z obu kolumn. Byaby to dusza lista, poniewa ze wzgldu na kod pocztowy, istnieje wicej unikalnych wierszy.
Powizanie typu nie potrafi jednak czyni cudw; obie listy kolumn musz zawiera jednakow ich liczb, a ponadto wybrane odpowiadajce sobie kolumny musz mie
zgodne typy. Popatrzmy:
66!27(
66!87-
66!87
#
!
8888888888
N!*!
/
$
$
"!
J$
66!27
Teraz, kiedy poznalimy instrukcje SQL zawierajce wicej ni jedn instrukcj ,
moemy zapozna si z ca klas instrukcji wyszukiwania danych, ktre cz instrukcje w o wiele bardziej wyszukany sposb. S one trudniejsze do zrozumienia ni
zapytania zoone z pojedynczej instrukcji lub powizania typu , ale s bardzo przydatne i otwieraj nowe moliwoci tworzenia kryteriw wyboru.
203
Zapytanie podrzdne ma miejsce wtedy, gdy tworzymy jeden (lub wicej) warunkw
0* instrukcji jako odrbn instrukcj .
Przypumy, e chcemy odnale wszystkie towary z tabeli 1-., z cen zakupu
(,#-"/1,.) wiksz ni 10. Instrukcja jest w tym przypadku raczej zoona ze
wzgldu na konieczno konwersji typu liczby na typ
:2; po to, aby typ liczby
by zgodny z typem kolumny ,#-"/1,. w tabeli 1-., ale w zasadzie jest do oczywista:
66!27
!"# /6$/!O+:KLK+ -D<?5
!=!/$6=/6$/!=!6$/!
888888888>8888888888888>888888888888>888888888888
:="'!=:;L?9=?:LH;
D=
$.!=:9L9J=:HLH;
::=6!!$=:HLD9=?;L9?
9$
66!27
Przypumy, e chcemy znale towary, ktrych cena zakupu jest wiksza od redniej
ceny zakupu. Z atwoci mona to zrobi w dwch zapytaniach:
66!27)*%
/1
#
A.
88888888888888
DL?FHKHKHKH:
:$
66!27
/1,)
56789)
66!87 +
5$7#
!=!/$6=/6$/!=!6$/!
888888888>888888888888888>888888888888>888888888888
:="'!=:;L?9=?:LH;
?= / !=DLF;=::LFH
;='/$!$!=DL;F=HLH;
J==HL?9=:;LD;
D=
$.!=:9L9J=:HLH;
::=6!!$=:HLD9=?;L9?
J$
66!27
Jest to jednak rozwizanie mao eleganckie. Tak naprawd chcemy przekaza wynik
pierwszego zapytania bezporednio do drugiego, bez koniecznoci pamitania go i wpisywania do drugiego zapytania.
Jest to wanie jedna z moliwoci, ktre daje zastosowanie zapyta podrzdnych. Moemy umieci pierwsze zapytanie w nawiasach i wykorzysta jako cz klauzuli 0*
w drugim zapytaniu:
66!27
+/1,
)*%
/1
66!87
#
!=!/$6=/6$/!=!6$/!
888888888>888888888888888>888888888888>888888888888
:="'!=:;L?9=?:LH;
?= / !=DLF;=::LFH
204
Jak widzimy, uzyskalimy ten sam wynik, ale bez koniecznoci wykonywania kroku poredniego oraz konwersji typw, poniewa wynik jest ju waciwego typu.
PostgreSQL najpierw wykonuje zapytanie w nawiasach. Po uzyskaniu odpowiedzi uruchamia zapytanie zewntrzne, zastpujc wynik zapytania wewntrznego. Jeeli zachodzi taka potrzeba, moemy korzysta z wielu zapyta podrzdnych dla rnych klauzul
0*. Nie ma ogranicze co do liczby, ale konieczno korzystania z wielu zagniedonych instrukcji wystpuje niezbyt czsto.
By moe kto powinien przyjrze si cenie ramek do obrazkw i sprawdzi, czy jest
waciwa!
Jak to dziaa
PostgreSQL skanuje zapytanie i stwierdza, e istniej dwa zapytania w nawiasach
zapytania podrzdne. Nastpnie rozwizuje te zapytania niezalenie, po czym przesya
odpowiedzi do waciwej czci klauzuli 0* zapytania gwnego i wykonuje to zapytanie.
205
Moglibymy zastosowa inne klauzule 0* lub + (). Poczenie warunkw 0*
pochodzcych z zapyta podrzdnych z warunkami konwencjonalnymi jest cakowicie
poprawne.
Spjrzmy na drugi rodzaj zapyta podrzdnych, gdzie w wyniku moe wystpi kilka
wierszy. Przypumy, e chcemy wiedzie, jakie towary, ktrych cena zakupu jest wiksza ni 10, znajduj si w magazynie. Moemy dowiedzie si tego za pomoc pojedynczej instrukcji nastpujcej postaci:
66!276/0$6:";
<$
66!876/1,)
-=6=) +
5$7) 46/0
66!876/0#
!=*
888888888>8888888888
:=:?
D=E
?$
66!27
Zauwamy, e dla skrcenia zapytania zastosowalimy aliasy nazw tabel (#-, bdzie
obecnie tabel #, 1-. tabel 1). Poczymy teraz dwie tabele (#!1-.1& 8
1!1-.1&) oraz dodamy w tabeli 1-. warunek dotyczcy ceny zakupu (1!,#-"/1,. =
>5!5
:2;).
Moemy take zapisa to zapytanie podrzdne stosujc sowo kluczowe , w celu zbadania listy wartoci. Naley zapisa zapytanie, ktre daje w wyniku list identyfikatorw towarw, dla ktrych cena zakupu towaru jest mniejsza ni 10.0:
!"# /6$/!O+:KLK+ -D<?5
206
Procedury te daj nam te same wyniki. Zapytania podrzdne chocia nie wszystkie
mona zazwyczaj zapisa jako powizania. Z tego wzgldu wane jest, aby je zrozumie. Tak jak w przypadku bardziej konwencjonalnych zapyta, mona zanegowa
warunek, zapisujc . Mona te wpisa dodatkowe klauzule 0* oraz warunki
+ ().
Czego powinnimy uy w przypadku, gdy mamy zapytanie podrzdne, ktre mona
zapisa jako powizanie? Naley rozway dwie sprawy czytelno i wydajno. Dla
okazyjnie wykorzystywanych zapyta dziaajcych z niewielkimi tabelami i wykonujcymi si szybko wykorzystujemy dowoln posta, ktra jest najbardziej czytelna. Jeeli
jest to zapytanie wykorzystywane czsto, dla duych tabel, opaca si zapisa je na rne sposoby i dowiadczalnie sprawdzi wydajno. By moe optymalizator zapyta
bdzie w stanie zoptymalizowa oba rodzaje i wydajno obu zapyta bdzie identyczna. Zwyciy wwczas zapytanie, ktre bdzie bardziej czytelne.
Naley ostronie bada wydajno instrukcji SQL. Istnieje wiele czynnikw znajduj%cych
si poza nasz% kontrol%, jak np. buforowanie danych przez system operacyjny.
Mona si take przekona, e wydajno zaley w bardzo duym stopniu od konkretnych danych w naszej bazie lub zmienia si diametralnie wraz ze zmian liczby wierszy
w poszczeglnych tabelach.
Nie poznalimy jeszcze ostatniego typu zapytania podrzdnego takiego, ktre bada
istnienie czego poniewa jest ono dosy zoone. Przed kocem rozdziau wrcimy
do tego typu zapyta.
207
Jeeli wydaje si to nam troch skomplikowane, to trzeba przyzna, e tak wanie jest.
Skorelowane zapytania podrzdne wykonywane s do nieefektywnie. Czasami jednak
udaje si dziki nim rozwiza bardzo zoone problemy. Tak wic dobrze wiedzie, e
istniej, nawet jeeli nieczsto bdziemy z nich korzysta.
208
Jak to dziaa?
Zapytanie rozpoczyna dziaanie od pobrania wiersza z tabeli /&./1?. Nastpnie wykonuje ono zapytanie podrzdne dla tabeli ,#-./, korzystajc z odnalezionej wartoci
,#-./1&. Wykonuje si zapytanie podrzdne poszukujc wierszy, gdzie pole ,#-
./1& z zewntrznego zapytania daje wiersz w tabeli ,#-./, ktry zawiera take
miasto Bingham. W przypadku znalezienia takiego wiersza, pole ,#-./1& jest przekazywane z powrotem do zapytania gwnego, ktre koczy klauzul 0* i jeeli jest
ona prawdziwa, wywietla kolumn &-.",.&. Zapytanie zewntrzne przechodzi nastpnie do kolejnego wiersza i sekwencja powtarza si.
Spjrzmy na inny przykad. Tym razem wykorzystamy trzeci typ zapytania, ktrego do
tej pory jeszcze nie poznalimy, gdzie zapytanie podrzdne bada istnienie czego.
Przypumy, e chcemy wyszczeglni wszystkich klientw, ktrzy skadali zamwienia. W naszej przykadowej bazie danych nie ma ich wielu. Pierwsza cz zapytania
jest prosta; zapiszmy:
C!<!
/!$/5
Zwrmy uwag, e zastosowalimy alias tabeli ,#-./ ,, ktry zosta przygotowany dla zapytania podrzdnego. Kolejna cz zapytania powinna sprawdzi, czy
warto pola ,#-./1& wystpuje take w tabeli /&./1?:
:
$!$C"# L/!$2/L/!$5
209
cza to, e jeeli zostan odnalezione jakiekolwiek dane, wynikiem zapytania bdzie 1,
co jest atwym i wydajnym sposobem powiedzenia 6-/.6. Moe to wydawa si dosy
dziwne, zatem zobaczmy:
66!27-
!"#
S/S
8888888888
:
:
:
9$
66!27
To dziaa, nawet jeli wyglda nieco dziwacznie. Wane jest, aby nie korzysta tu
z funkcji , poniewa potrzebujemy wyniku z kadego wiersza, gdzie kolumna
- ma warto (1@7, a nie informacji, ilu mamy klientw pochodzcych z Bingham.
Drug wan rzecz, na ktr naley zwrci uwag jest fakt, e skorzystalimy z tabeli
,#-./ w tym zapytaniu podrzdnym, ktre w zasadzie byo uyte w zapytaniu gw-
Mona tu zobaczy, jak s zapisywane skorelowane zapytania podrzdne. Czasami, kiedy napotkamy problem, ktry wydaje si niemoliwy do rozwizania za pomoc zwykych zapyta SQL, moe si okaza, e rozwizaniem tych trudnoci jest skorelowane
zapytanie podrzdne.
210
Zapisalimy dane, ale w jaki sposb uzyskamy informacje o tym, ktre pojedyncze czci skadaj si na poszczeglny komponent? Musimy powiza tabel z ni sam.
Okazuje si to dosy proste. Musimy zastosowa aliasy nazw tabel, a nastpnie zapisa
klauzul 0* odnoszc si do tej samej tabeli, stosujc jednak rne nazwy:
66!271-601$17601
1"1-$1"17
66!871-61"/01761"/1"/0#
!/$6=!/$6
888888888888888888>8888888888888
!/4$=/4$
!/4$= !
?$
66!27
211
To dziaa, ale jest troch mylce, poniewa mamy dwie kolumny wyniku z t sam nazw.
Moemy w atwy sposb poprawi t niedogodno za pomoc sowa kluczowego :
66!271-601)@>0@$17601)@&"@
66!87
1"1-$1"171-61"/01761"/1"/0#
!='$
888888888888888888>8888888
!/4$=/4$
!/4$= !
?$
66!27
Ostatnim gwnym zagadnieniem, jakie poruszymy w tym rozdziale, jest klasa powiza znana jako powizania zewntrzne. S one podobne do powiza konwencjonalnych, ale wykorzystuj nieco inn skadni. Z tego wzgldu odoylimy spotkanie
z nimi na koniec tego rozdziau.
Spjrzmy na nasze tabele 1-. i #-,:
Rysunek 7.2.
212
213
214
Wyglda to niemal na zbyt proste, aby mogo by prawdziwe. Sprbujmy zatem zobaczy dziaanie podanej wyej skadni:
66!276/0$6:";
A+ <
66!87 6/06/0#
!=*
888888888>8888888888
:=:?
?=?
9=
F=E
;=9
J=
D=E
E=:E
H=
:K=:
::=
::$
66!27
215
Dla warunku 1-., ktry dotyczy wszystkich wierszy, zastosujemy klauzul 0*:
"# L/6$/!O+;LK+ -D<?5
Jak to dziaa?
Aby uzyska wszystkie wartoci z tabeli 1-., opcjonalnie w poczeniu z tabel #-,,
gdzie istniej oba wiersze, a warto pola $-1- jest wiksza ni 2, stosujemy mechanizm <
. Daje to nam zbir, w ktrym znajd si wszystkie wiersze
z tabeli 1-., ale kolumna $-1- z tabeli #-, bdzie zawieraa warto , chyba
e obydwie tabele zawieraj zapis dla danego towaru oraz warto pola $-1- jest
wiksza ni 2. Nastpnie stosujemy klauzul 0*, ktra pozwala na wywietlanie tylko
tych wierszy, w ktrych cena zakupu (,#-"/1,. z tabeli 1-.) jest wiksza ni 5.0.