06 Rozdziaę 05


Rozdział 5
Praktyczne wprowadzenie do języka
SQL
Zadaniem tego rozdziału jest przynajmniej częściowe rozwianie aury
tajemniczości, otaczającej SQL. Mimo że SQL jest stosunkowo prostym językiem,
proces jego poznawania może być bardzo zniechęcający, szczególnie w przypadku
osób, które nigdy wcześniej nie miały z nim kontaktu. Powodem jest powszechnie
spotykany sposób prezentacji języka SQL w książkach i materiałach
szkoleniowych. W ramach jednej sesji omawiane są wszystkie elementy składni
każdego z poleceń, a całość okraszona jest sporą dawką teorii relacyjnych baz
danych. Czytelnik musi samodzielnie posortować wszystkie informacje i wybrać te
rzeczywiście istotne.
Niniejszy rozdział skonstruowany jest inaczej. Czytelnik prowadzony będzie krok
po kroku przez proces tworzenia obiektów bazy danych, dodawania wierszy tabel
i formułowania zapytań. Omawiany rozdział ma jak najszybciej i jak najprościej
dostarczyć podstawowych informacji o języku SQL. Zwięzłość nie oznacza jednak
braku ścisłości, a jedynie pominięcie mniej istotnych zagadnień.
Przewodnik po języku SQL podzielony został na dwie części. Z pierwszą częścią,
zatytułowaną  Szybki start , można zapoznać się w trakcie jednej sesji. W drugiej
części znalezć można rozwinięcie pewnych zagadnień, poruszonych w części
pierwszej. Jednak również druga część dotyczy wyłącznie zagadnień
podstawowych. Zaawansowane możliwości języka SQL omówiono w rozdziale 24.
UWAGA:
Od Czytelnika nie oczekuje się wcześniejszej znajomości języka SQL. Czytelnicy,
którzy znają już podstawy tego języka i dysponują pewnym doświadczeniem,
mogą pominąć niniejszy rozdział i od razu przejść do Rozdziału 6,  Projektowanie
baz danych w modelu klient-serwer .
116 Część I
UWAGA:
Zakładamy, że Czytelnik dysponuje serwerem baz danych SQL i mechanizmem
przesyłania poleceń SQL do tego serwera. W przykładach, zawartych
w niniejszym rozdziale, stosowany jest serwer Local InterBase, dostarczany
w pakiecie Delphi Client/Server. Zamiast niego można jednak użyć dowolnego
serwera, w miarę możliwości zgodnego ze specyfikacją SQL ANSI  92.
Szybki start
Języka SQL najlepiej uczyć się na przykładach i przy pomocy praktycznych
ćwiczeń. Zapraszamy zatem do nauki.
UWAGA:
Wielokrotnie w tym rozdziale podnoszony jest problem różnic i niezgodności
między dwiema rodzinami dialektów SQL - rodziną Sybase i ANSI. Sybase SQL
Server i jego kuzyn, opracowany na podstawie licencji - Microsoft SQL Server -
korzystają z dialektu, którego składnia pod wieloma względami istotnie różni się
od standardu ANSI. Z kolei InterBase, Oracle i większość pozostałych systemów
zarządzania bazami danych zachowuje daleko posuniętą zgodność ze standardem
ANSI SQL, przy czym każdy z producentów uzupełnia dialekt własnymi
rozszerzeniami. Przykłady, przytaczane w tym rozdziale, zapisane są w dialekcie
InterBase, a wiele z nich nie będzie działać na serwerze SQL Server bez
odpowiednich modyfikacji. Należy także pamiętać, że ilekroć omawiany jest
dialekt Sybase, można przyjąć, że ta sama składnia obowiązywać będzie
w przypadku serwera Microsoft SQL Server. Analogicznie, ilekroć omawiana jest
składnia Interbase, można bezpiecznie założyć, że będzie ona również
obowiązywać w przypadku systemów innych producentów, zgodnych z ANSI,
w tym w systemie Oracle.
Wybór edytora SQL
Jedną z pierwszych decyzji adepta języka SQL musi być wybór odpowiedniego
edytora. Edytor SQL jest narzędziem, służącym do wprowadzania i uruchamiania
poleceń SQL. We wszystkich przykładach w niniejszym rozdziale stosowany jest
edytor Windows Interactive SQL (WISQL), dostarczany razem z serwerem Local
Interbase. Proponujemy korzystanie z tego narzędzia w początkowym okresie
zapoznawania się z językiem. Użytkownicy serwera Sybase SQL mogą skorzystać
z dołączonego do niego edytora ISQL. Z kolei użytkownicy Oracle mogą stosować
SQL*Plus. Dostępne są także edytory niezależnych producentów, takie jak
Desktop DBA firmy Datura albo DB Artisan firmy Embarcadero. W każdym
Rozdział 5 Praktyczne wprowadzenie do języka SQL 117
przypadku stosowane narzędzie musi wysyłać polecenia SQL do serwera oraz
wyświetlać wszelkie odpowiedzi z serwera i wyniki.
Terminatory SQL
W języku SQL występują dwa rodzaje terminatorów: terminatory poleceń
i terminatory wsadowe. W niektórych dialektach SQL wymagane jest kończenie
każdego polecenia terminatorem. Na przykład InterBase i Oracle wymagają, aby
każde polecenie kończyło się średnikiem (;). Terminatory poleceń są z reguły
związane z konkretnym dialektem SQL, a nie z narzędziem przesyłającym
polecenia do serwera.
Z kolei terminatory wsadowe kończą ciąg poleceń SQL. Wystąpienie takiego
terminatora powoduje przesłanie ciągu poleceń do serwera, w celu ich
przetworzenia. Formę terminatora wsadowego narzuca często narzędzie, a nie sam
dialekt SQL. Na przykład, edytor ISQL z pakietu Sybase wymaga, aby ciąg
poleceń SQL kończył się słowem kluczowym GO (istnieje możliwość zmiany
postaci terminatora), mimo że słowo GO nie należy do dialektu Transact-SQL
firmy Sybase, a po faktycznym przesłaniu go do serwera wystąpiłby błąd.
W edytorze WISQL, stosowanym we wszystkich przykładach w niniejszym
rozdziale, terminator w postaci średnika jest opcjonalny. Polecenia, wpisywane
w WISQL, będą wykonywane niezależnie od tego, czy kończą się średnikiem, czy
też nie.
UWAGA:
Definiując i kompilując procedury pamiętane i inne elementy programu na
platformie InterBase należy pamiętać, że komendy SQL, zapisane w ramach
polecenia definiującego, muszą kończyć się terminatorem - niezależnie od
stosowanego edytora. Niektóre polecenia SQL, w tym polecenie CREATE
PROCEDURE, same składają się z szeregu poleceń, które nie powinny być
wykonywane na etapie tworzenia procedury w edytorze SQL. Dlatego na czas
tworzenia procedury należy czasowo zmienić domyślny terminator edytora,
korzystając z polecenia SET TERMINATOR. Zagadnienie to omówiono
szczegółowo w rozdziale 24.
Zakładanie bazy danych
Do praktycznego wypróbowania przykładów z dalszej części niniejszego rozdziału
niezbędna jest baza danych, w której będzie można utworzyć kilka tymczasowych
tabel. Założenie takiej bazy danych nie jest trudnym zadaniem. W języku SQL do
tego celu służy polecenie CREATE DATABASE. Szczegóły składni tego polecenia
118 Część I
różnią się w systemach różnych producentów. Oto przykładowy zapis w dialekcie
InterBase:
CREATE DATABASE "C:\DATA\IB\ORDENT.GDB"
USER "SYSDBA" PASSWORD "masterkey";
Aby utworzyć bazę danych, należy wpisać powyższe polecenie w edytorze
InterBase ISQL. Można również skorzystać z opcji Create Database z menu File
narzędzia WISQL. Oto szczegółowa procedura postępowania:
1. Uruchomić program Windows Interactive SQL (WISQL) - powinien on
znajdować się w folderze programu Delphi.
2. Wybrać opcję Create Database z menu File programu WISQL.
3. Na ekranie pojawi się okno dialogowe Create Database. W polu Database
należy wpisać C:\DATA\IB\ORDENT (w miejsce C:\DATA\IB należy
wpisać poprawną ścieżkę dostępu). Oczywiście wskazane jest wcześniejsze
utworzenie katalogu, w którym przechowywane będą obiekty bazy danych.
4. W odpowiednich polach okna dialogowego wpisać identyfikator użytkownika
i hasło. Jeśli hasło użytkownika SYSDBA nie zostało zmienione, to powinno
ono brzmieć masterkey. Na razie można pozostać przy tym haśle. Przy
wprowadzaniu hasła należy pamiętać, że InterBase rozróżnia w tym przypadku
duże i małe litery.
5. Kliknąć OK. InterBase utworzy bazę danych i podłączy do niej użytkownika.
W przyszłości podłączanie do istniejącej już bazy danych realizowane będzie
przy pomocy polecenia Connect to Database z menu File.
Tworzenie tabel
Po założeniu bazy danych przystąpić można do tworzenia poszczególnych
obiektów bazy. Rozpoczniemy od utworzenia trzech tabel. Wykorzystamy do tego
polecenie SQL CREATE TABLE. Aby utworzyć pierwszą tabelę należy
w edytorze SQL wpisać i spowodować wykonanie następującego polecenia:
CREATE TABLE CUSTOMER
{
CustomerNumber int NOT NULL,
LastName char(30) NOT NULL,
FirstName char(30) NOT NULL,
StreetAddress char(30) NOT NULL,
City char(20) NOT NULL,
State char(2) NOT NULL,
ZIP char(10) NOT NULL
}
Rozdział 5 Praktyczne wprowadzenie do języka SQL 119
Powyższe polecenie tworzy tabelę CUSTOMER (KLIENT). Podobnego polecenia
można użyć do stworzenia tabeli ORDERS (ZAMÓWIENIA).
CREATE TABLE ORDERS
{
OrderNumber int NOT NULL,
OrderDate date NOT NULL,
CustomerNumber int NOT NULL,
ItemNumber int NOT NULL,
Amount numeric(9,2) NOT NULL
}
Teraz pozostała jeszcze do utworzenia tabela ITEMS (TOWARY). Oto
odpowiednie polecenie SQL:
CREATE TABLE ITEMS
{
ItemNumber int NOT NULL,
Description char(30) NOT NULL,
Price numeric(9,2) NOT NULL
}
UWAGA:
W przypadku większości serwerów nie ma obowiązku wpisywania klauzuli
NULL/NOT NULL. Należy jednak zwrócić uwagę, że różne serwery przyjmują
różne wartości domyślne w przypadku jej pominięcia. Na przykład InterBase
zachowuje się zgodnie ze standardem ANSI SQL i dla kolumn, dla których autor
programu nie określił preferencji, przyjmuje domyślnie klauzulę NULL. Z kolei
SQL Server przyjmuje jako domyślną klauzulę NOT NULL. Wskazane jest zatem
jawne wpisywanie klauzuli NULL/NOT NULL. Zasady tej nie można jednak
zastosować do serwera InterBase, który nie zezwala na wpisanie klauzuli NULL,
gdyż jest ona przyjmowana jako domyślna. Polecenie tworzące tabelę
i zawierające klauzulę NULL dla którejkolwiek z kolumn, nie zostanie przyjęte
przez serwer InterBase.
Wpisywanie danych
Do wpisywania danych do tabel (po jednym pełnym wierszu) służy polecenie SQL
INSERT. Poniżej zapisano polecenia, dodające wiersze danych kolejno do
wszystkich trzech tabel. Wprowadzenie i wykonanie poniższych poleceń
spowoduje dopisanie trzech wierszy do tabeli CUSTOMER:
INSERT INTO CUSTOMER
120 Część I
VALUES(1,'Doe', 'John','123
Ą' Sunnylane','Anywhere','OK','73115')
INSERT INTO CUSTOMER
VALUES(2,'Doe','Jane', '123
Ą' Sunnylane','Anywhere','OK','73115')
INSERT INTO CUSTOMER
VALUES(3,'Citizen','John','57 Riverside','Reo','MO','65803')
Następnie należy dodać cztery wiersze do tabeli ORDERS:
INSERT INTO ORDERS
VALUES(101,'07/07/97',1,1001,123.45)
INSERT INTO ORDERS
VALUES(102,'07/08/97',2,1002,678.90)
INSERT INTO ORDERS
VALUES(103,'07/09/97',3,1003,86753.09)
INSERT INTO ORDERS
VALUES(104,'07/10/97',1,1002,678.90)
UWAGA:
Dopisując wiersze do tabel w systemie Oracle należy zwrócić uwagę na poprawny
format daty. Domyślnie przyjmowany przez Oracle format zapisu daty jest
uzależniony od ustawień międzynarodowych systemu i wartości parametru
inicjalizacyjnego NLS_DATE_FORMAT. Na serwerze autora jako domyślny
przyjmowany jest format daty 'DD-MMM-YY', a zatem polecenia dodające
wiersze to tabeli ORDER przyjmą postać:
INSERT INTO ORDERS
VALUES(101,'07-JUL-97',1,1001,123.45)
INSERT INTO ORDERS
VALUES(102,'08-JUL-97',2,1002,678.90)
INSERT INTO ORDERS
VALUES(103,'09-JUL-97',3,1003,86753.09)
INSERT INTO ORDERS
VALUES(104, 10-JUL-97',1,1002,678.90)
Datę, zapisaną w dowolnym formacie, można również poddać konwersji przy
pomocy funkcji Oracle TO_DATE(), na przykład:
INSERT INTO ORDERS
VALUES(101,TO_DATE('07/07/97','MM/DD/YY'),1,1001,123.45)
INSERT INTO ORDERS
VALUES(102, TO_DATE('07/08/97','MM/DD/YY'),2,1002,678.90)
INSERT INTO ORDERS
VALUES(103, TO_DATE('07/09/97','MM/DD/YY'),3,1003,86753.09)
Rozdział 5 Praktyczne wprowadzenie do języka SQL 121
INSERT INTO ORDERS
VALUES(104, TO_DATE('07/10/97','MM/DD/YY'),1,1002,678.90)
Wreszcie, poniższe trzy polecenia dodają wiersze do tabeli ITEMS:
INSERT INTO ITEMS
VALUES(1001,'WIDGET A',123.45)
INSERT INTO ITEMS
VALUES(1002,'WIDGET B',678.90)
INSERT INTO ITEMS
VALUES(1003,'WIDGET C',86753.09)
Należy zwrócić uwagę, że żadne z powyższych poleceń INSERT nie zawiera listy
pól, a jedynie listę wartości. W swojej standardowej postaci polecenie INSERT
wpisuje wartości do wszystkich kolumn w tabeli, w kolejności, w jakiej kolumny
te występują w definicji struktury tabeli. W każdym poleceniu INSERT można
jednak określić listę pól:
INSERT INTO ITEMS (ItemNumber,Price)
VALUES(1001,123.45)
Kolejność pól na liście nie musi odpowiadać kolejności, w jakiej występują one
w tabeli; należy jednak pamiętać, że kolejność wartości, wymienionych
w poleceniu INSERT, musi odpowiadać kolejności, w jakiej w tym samym
poleceniu wymieniono pola. Oto przykład poprawnego polecenia:
INSERT INTO ITEMS (Price, ItemNumber)
VALUES(123.45,1001)
Polecenie SELECT.
Do przejrzenia zawartości każdej z tabel wykorzystać można polecenie SQL
SELECT, w postaci SELECT * FROM tablename (w miejsce tablename
należy wpisać nazwę tabeli, której zawartość ma być odczytywana, np.
CUSTOMER, ORDERS albo ITEMS). Jeśli wszystkie dotychczasowe przykłady
zostały dokładnie wprowadzone, to tabele CUSTOMER i ITEMS powinny
zawierać po trzy wiersze, a tabela ORDERS - cztery.
Na rysunku 5.1 przedstawiono zawartość tabeli CUSTOMER, wyświetloną po
wykonaniu polecenia SELECT * FROM CUSTOMER w programie WISQL.
122 Część I
Rysunek 5.1.
Zawartość tabeli
CUSTOMER
wyświetlona
w programie
WISQL.
Na rysunku 5.2 przedstawiono zawartość tabeli ORDERS, wyświetloną po
wykonaniu polecenia SELECT * FROM ORDERS.
Rysunek 5.2.
Zawartość tabeli
ORDER
wyświetlona
w programie
WISQL.
Na rysunku 5.3 przedstawiono zawartość tabeli ITEMS, wyświetloną po
wykonaniu polecenia SELECT * FROM ITEMS.
Rozdział 5 Praktyczne wprowadzenie do języka SQL 123
Rysunek 5.3.
Zawartość tabeli
ITEMS
wyświetlona
w programie
WISQL.
UWAGA:
Implementacje klauzuli FROM na poszczególnych platformach systemowych różnią
się od siebie. Na niektórych platformach klauzula ta jest obowiązkowa, na innych
występuje opcjonalnie. Na przykład dialekty Oracle i InterBase wymagają użycia
klauzuli FROM również wówczas, gdy polecenie SELECT nie wybiera kolumn
tabeli. Z kolei Sybase SQL Server wymaga klauzuli FROM tylko przy wybieraniu
kolumn tabeli. Polecenie SELECT, które nie dotyczy kolumn tabeli (lecz np. tylko
wyrażeń albo funkcji systemowych), nie musi zawierać klauzuli FROM. Klauzulę tę
można pominąć, wybierając np. funkcję systemową, taką jak getdate(). Z kolei
wybierając funkcję SYSDATE w systemie Oracle trzeba koniecznie umieścić
w poleceniu SELECT klauzulę FROM.
Polecenie SELECT * zwraca wszystkie kolumny tabeli. W miejsce gwiazdki
można wpisać listę nazw pól, oddzielonych przecinkami, np.:
SELECT CustomerNumber, LastName, State FROM Customer
Taki zapis pozwala wybrać pola, których zawartość ma być zwrócona. rysunek 5.4
przedstawia wynik powyższego zapytania.
124 Część I
Rysunek 5.4.
Polecenie SELECT
z listą pól.
Wyrażenia
W poleceniu SELECT w miejsce kolumn wpisać można także wyrażenia,
zawierające wartości i funkcje. Niektóre dialekty SQL oferują funkcje, zwracające
użyteczne informacje, a jednocześnie wcale nie odwołujące się do kolumn.
Poniższe przykładowe polecenie, przeznaczone dla systemu Sybase albo Microsoft
SQL Server, zwraca aktualną datę i czas:
SELECT getdate()
Z kolei poniższe polecenie, zapisane w dialekcie InterBase, zwraca nazwisko
każdego klienta z tabeli CUSTOMER, zapisane dużymi literami (zob. rysunek
5.5):
SELECT UPPER(LastName), First Name
FROM CUSTOMER
Rysunek 5.5.
Przykład użycia
funkcji UPPER
w poleceniu
SELECT.
Rozdział 5 Praktyczne wprowadzenie do języka SQL 125
Funkcje sumujące
Funkcje sumujące (ang. aggregate columns) wykonują obliczenia na zbiorze
danych. Należą do nich np. funkcje COUNT, SUM, AVG, MIN, STDDEV,
VARIANCE i MAX. Poniższe przykłady ilustrują użycie niektórych z nich.
SELECT COUNT(*) FROM CUSTOMER
Powyższe polecenie zwraca liczbę rekordów w tabeli CUSTOMER.
SELECT MAX(Amount) FROM ORDERS
Z kolei powyższe polecenie zwraca wartość największego (pod względem kwoty)
zamówienia w tabeli ORDERS, a poniższy przykład - sumę kwot wszystkich
zamówień w tabeli:
SELECT SUM(Amount) FROM ORDERS
Klauzula WHERE
Klauzula SQL WHERE określa, które wiersze ma zwrócić polecenie SELECT. Oto
kilka przykładów:
SELECT * FROM CUSTOMER
WHERE State='OK'
Powyższe polecenie zwróci informacje tylko o tych klientach, którzy mieszkają
w stanie Oklahoma (OK) - zob. rysunek 5.6.
Rysunek 5.6.
Ilustracja
zastosowania
klauzuli WHERE
w poleceniu
SELECT,
Kolejny przykład, zilustrowany na rysunku 5.7, zwróci informacje o klientach,
w których adresie występuje słowo  Sunny .
SELECT LastName, StreetAddress FROM CUSTOMER
WHERE StreetAddress LIKE '%Sunny%'
126 Część I
Rysunek 5.7.
Ilustracja
zastosowania
klauzuli WHERE
ze słowem LIKE
w poleceniu
SELECT,
Poniższy przykład zwraca listę zamówień, których wartość przekracza 500
dolarów - zob. rysunek 5.8.
SELECT OrderNumber, OrderDate, Amount FROM ORDERS
WHERE Amount > 500
Rysunek 5.8.
Zamówienia,
których wartość
przekracza 500
dolarów.
Kolejny, ostatni przykład, zwraca listę zamówień złożonych pomiędzy 8 a 9 lipca
1997 (włącznie). Rezultat przedstawiono na rysunku 5.9.
SELECT OrderNumber, OrderDate, Amount FROM ORDERS
WHERE OrderDate BETWEEN '07/08/97' AND '07/09/97'
Rozdział 5 Praktyczne wprowadzenie do języka SQL 127
Rysunek 59.
Ilustracja
zastosowania
klauzuli WHERE
ze słowem
BETWEEN.
Złączenia
Klauzula WHERE bywa także używana do złączenia (ang. join) dwóch tabel
i wygenerowania złożonego wynikowego zbioru danych. Aby uzyskać złączenie
tabel, należy wprowadzić dwie modyfikacje do podstawowej formy polecenia
SELECT: w klauzuli FROM należy wymienić dodatkowe tabele, a w klauzuli
WHERE - połączyć skojarzone pola (zob. rysunek 5.10). Oto przykład:
SELECT CUSTOMER.CustomerNumber, ORDERS.Amount
FROM CUSTOMER, ORDERS
WHERE CUSTOMER.CustomerNumber=ORDERS.CustomerNumber
Rysunek 5.10.
Tabela
CUSTOMER
złączona z tabelą
ORDERS.
W powyższym przykładzie zwraca uwagę obecność tabeli ORDERS w klauzuli
FROM, a także zastosowanie znaku równości, który łączy tabele CUSTOMER
i ORDERS, kojarząc ich pola CustomerNumber. Tabelę, wymienioną po lewej
stronie znaku równości, nazywamy tabelą zewnętrzną, zaś tabela po prawej stronie
128 Część I
to tabela wewnętrzna. Równie powszechnie stosowane są określenia: tabela lewa
i prawa, co identyfikuje pozycję danej tabeli w złączeniu lewostronnym ( left join),
które jest najpopularniejszym rodzajem złączenia w systemach zarządzania
relacyjnymi bazami danych.
Złączenia wewnętrzne i zewnętrzne
Omawiane dotychczas złączenie znane jest pod oficjalną nazwą złączenia
wewnętrznego (ang. inner join). Wynikiem złączenia wewnętrznego są tylko te
wiersze, dla których spełniony jest warunek złączenia. W przypadku złączenia
zewnętrznego (ang. outer join) wiersze zwracane są niezależnie od tego, czy
spełniony jest dla nich warunek złączenia. Jeśli dla danego wiersza warunek nie
jest spełniony, w miejsce wartości pól z tabeli wewnętrznej podstawiana jest
wartość NULL.
Formy poleceń, realizujących złączenie zewnętrzne, różnią się w zależności od
rodzaju stosowanego serwera i wariantu ANSI SQL, obsługiwanego przez serwer.
Występują dwie wersje podstawowej formy takiego polecenia. W dialekcie
Sybase/Microsoft SQL Server złączenie zewnętrzne realizowane jest przez np.
takie polecenie:
SELECT CUSTOMER.CustomerNumber, ORDERS.Amount
FROM CUSTOMER, ORDERS
WHERE CUSTOMER.CustomerNumber*=ORDERS.CustomerNumber
Należy zwrócić uwagę na gwiazdkę, umieszczoną z lewej strony znaku równości.
W dialekcie SQL Server tak umiejscowiona gwiazdka oznacza lewostronne
złączenie zewnętrzne. Istnieją również prawostronne złączenia zewnętrzne - są one
jednak znacznie rzadziej stosowane. W dialekcie SQL Server prawostronne
złączenie zewnętrzne zapisuje się podobnie, jak odpowiednie złączenie
lewostronne, z tym że gwiazdka musi znajdować się po prawej stronie znaku
równości:
SELECT CUSTOMER.CustomerNumber, ORDERS.Amount
FROM CUSTOMER, ORDERS
WHERE CUSTOMER.CustomerNumber=*ORDERS.CustomerNumber
Prawostronne złączenia zewnętrzne najlepiej nadają się do wyszukiwania
"osieroconych" kluczy, które występują w tabeli po prawej stronie, ale nie w tabeli
po lewej stronie.
Polecenie złączenia w dialekcie ANSI
Polecenie lewostronnego złączenia zewnętrznego w dialekcie ANSI przyjmuje
następującą postać (zob. rysunek 5.11):
SELECT CUSTOMER.CustomerNumber, ORDERS.Amount
FROM CUSTOMER LEFT OUTER JOIN ORDERS
Rozdział 5 Praktyczne wprowadzenie do języka SQL 129
ON CUSTOMER.CustomerNumber=ORDERS.CustomerNumber
W przypadku złączeń prawostronnych zewnętrznych i lewostronnych
wewnętrznych należy zastąpić słowo LEFT (lewostronne) słowem RIGHT
(prawostronne) albo OUTER (zewnętrzne) słowem INNER (wewnętrzne).
UWAGA:
Serwer InterBase nie dopuszcza stosowania konwencji Sybase w zapisie złączeń
zewnętrznych w klauzuli WHERE; dozwolona jest jedynie składnia ANSI. InterBase
dopuszcza natomiast realizowanie złączeń wewnętrznych przy użyciu klauzuli
WHERE.
Rysunek 5.11.
Złączenie
zewnętrzne tabel
CUSTOMER
i ORDERS przy
użyciu polecenia
ANSI-SQL.
Podzapytania
Podzapytanie jest to polecenie SELECT, zawarte w klauzuli WHERE innego
zapytania, a zatem definiujące zbiór danych zwracany przez zapytanie (zob.
rysunek 5.12). W ogólnym przypadku podzapytania zwracają listę elementów,
która jest następnie używana w warunku zapytania nadrzędnego. Oto przykład:
SELECT * FROM CUSTOMER
WHERE CustomerNumber IN (SELECT CustomerNumber FROM ORDERS)
130 Część I
Rysunek 5.12.
Podzapytanie,
zawarte w klauzuli
WHERE innego
zapytania.
GROUP BY
SQL jest językiem zapytań zorientowanym na przetwarzanie zbiorów, a nie
pojedynczych rekordów, dlatego jego integralnym składnikiem są polecenia
grupujące dane. Właśnie te polecenia, wraz z funkcjami sumującymi, stosowane są
w praktyce do uzyskiwania odpowiedzi na złożone zapytania, dotyczące
zawartości bazy danych. Programistom, korzystającym dotąd z języków rodziny
dBASE i przyzwyczajonym do przetwarzania danych po jednym rekordzie,
zapytania zorientowane na przetwarzanie zbiorów wydają się początkowo
nienaturalne. W programach do obsługi bazy danych, stworzonych specjalnie dla
komputerów klasy PC, wszelkie zestawienia zbiorcze uzyskuje się w wyniku
działania pętli, przetwarzającej kolejne rekordy. W środowisku SQL problemy
tego rodzaju rozwiązuje się zupełnie inną drogą. Pojedynczymi poleceniami SQL
można rozwiązywać zadania, które w języku Xbase wymagałyby wpisania 10 lub
nawet 50 wierszy programu. Taka zwięzłość jest wynikiem umiejętnego
stosowania polecenia SELECT z klauzulą GROUP BY oraz funkcji sumujących
SQL. Poniższy przykład ilustruje użycie klauzuli GROUP BY:
SELECT CUSTOMER.CustomerNumber, sum(ORDERS.Amount)
Ą' TotalOrders
FROM CUSTOMER, ORDERS
WHERE CUSTOMER.CustomerNumber=ORDERS.CustomerNumber
GROUP BY CUSTOMER.CustomerNumber
Powyższe zapytanie zwraca listę klientów, wraz z sumami wartości ich wszystkich
zamówień (zob. rysunek 5.13).
Rozdział 5 Praktyczne wprowadzenie do języka SQL 131
Rysunek 5.13
Zapytanie
wykorzystujące
klauzulę GROUP
BY
Skąd wiadomo, które pola mają znalezć się w klauzuli GROUP BY? Jako regułę
należy przyjąć umieszczanie w tej klauzuli wszystkich pól z listy kolumn polecenia
SELECT, z wyjątkiem funkcji sumujących i wartości. Jako przykład rozważymy
następujące polecenie SELECT:
SELECT CUSTOMER.CustomerNumber, CUSTOMER.LastName,
[ccc] CUSTOMER.State, sum(ORDERS.Amount) TotalOrders
FROM CUSTOMER, ORDERS
WHERE CUSTOMER.CustomerNumber=ORDERS.CustomerNumber
Takie polecenie należałoby uzupełnić następującą klauzulą GROUP BY:
GROUP BY CUSTOMER.CustomerNumber, CUSTOMER.LastName,
Ą' CUSTOMER.State
Niektóre serwery, w tym Oracle i InterBase, wymuszają stosowanie powyższej
reguły - nie spróbują nawet wykonać zapytań, które ją naruszają. Inne serwery,
w tym SQL Server, podejmą próbę wykonania zapytania, jednak uzyskane wyniki
najprawdopodobniej nie będą odpowiadały oczekiwaniom. Rozważmy następujące
zapytanie:
SELECT CUSTOMER.LastName, COUNT(*) NumberWithName
FROM CUSTOMER
Można by oczekiwać, że zapytanie to zwróci listę wszystkich nazwisk (LastName)
z tabeli CUSTOMER i dla każdego nazwiska poda liczbę jego wystąpień. Wynik
będzie jednak inny. Jak już wspomniano, InterBase w ogóle nie wykona
powyższego polecenia, gdyż brakuje w nim klauzuli GROUP BY. Z kolei SQL
Server wykona polecenie, ale w każdym zwróconym wierszu umieści liczbę
wszystkich rekordów w tabeli, a nie tylko tych, które zawierają określone
nazwisko. Tego rodzaju błędnie skonstruowane zapytania rozpoznać można po
tym, że wynik funkcji sumującej jest identyczny we wszystkich zwróconych
wierszach. W przypadku dużych zbiorów danych czas wykonania takich zapytań
będzie bardzo długi. Przykładowe zapytanie NumberWithName dla każdego
132 Część I
wiersza wynikowego zwróciłoby całkowitą liczbę wierszy w tabeli. Poprawione
zapytanie przyjmie postać:
SELECT CUSTOMER.LastName, COUNT(*) NumberWithName
FROM CUSTOMER
GROUP BY CUSTOMER.LastName
Powyższe zapytanie zwróci listę nazwisk z tabeli CUSTOMER, a dla każdego
nazwiska poda liczbę jego wystąpień. Ilustruje to rysunek 5.14.
Rysunek 5.14.
Wyniki poprawnie
skonstruowanego
zapytania
Having
Klauzula HAVING służy do ograniczania zbioru wierszy, zwracanych w wyniku
wykonania klauzuli GROUP BY. Między HAVING a GROUP BY występuje
zależność podobna do tej, która wiąże klauzulę WHERE z poleceniem SELECT.
W przeciwieństwie do klauzuli WHERE, która operuje na wierszach tabel
podawanych w zapytaniu, HAVING działa na zbiorze wierszy wynikowych (zob.
rysunek 5.15).
Rozdział 5 Praktyczne wprowadzenie do języka SQL 133
Rysunek 5.15.
Zastosowanie
klauzuli HAVING
do ograniczenia
zbioru wierszy,
zwracanych przez
klauzulę GROUP
BY.
Prawie zawsze można uzyskać analogiczne ograniczenie zbioru wynikowego, nie
stosując przy tym klauzuli HAVING. W ogólnym przypadku HAVING oferuje
mniejszą wydajność niż klauzula WHERE, gdyż ogranicza dopiero pogrupowany
zbiór wynikowy; WHERE realizuje ograniczenie jeszcze przed pogrupowaniem
zbioru wynikowego. Oto przykład użycia klauzuli HAVING:
SELECT CUSTOMER.LastName, COUNT(*) NumberWithName
FROM CUSTOMER
GROUP BY CUSTOMER.LastName
HAVING CUSTOMER.LastName<>'Citizen'
W poprawnie skonstruowanym zapytaniu kryterium wyboru powinno znalezć się
w klauzuli WHERE:
SELECT CUSTOMER.LastName, COUNT(*) NumberWithName
FROM CUSTOMER
WHERE CUSTOMER.LastName<>'Citizen'
GROUP BY CUSTOMER.LastName
Niektóre serwery (np. Sybase SQL Server) wykrywają niewłaściwe użycie klauzuli
HAVING i przed wykonaniem zapytania - w procesie jego optymalizacji -
automatycznie wprowadzają korektę. W przypadku innych serwerów należy zatem
zachować ostrożność, szczególnie przy tworzeniu zapytań operujących na dużych
tabelach. W systemach, które nie wykrywają błędnego użycia klauzuli HAVING,
umieszczenie jej w niewłaściwym miejscu z reguły blokuje możliwość użycia
indeksów przy generowaniu wyników zapytań.
ORDER BY
Klauzula ORDER BY określa kolejność wierszy w zbiorze wynikowym (zob.
rysunek 5.16). Jej użycie ilustruje poniższy przykład:
SELECT LastName, State FROM CUSTOMER
ORDER BY State
134 Część I
Rysunek 5.16.
Zastosowanie
klauzuli ORDER
BY.
Oto jeszcze jeden przykład:
SELECT FirstName, LastName
FROM CUSTOMER
ORDER BY LastName
Aliasy kolumn
W niektórych prezentowanych przykładach funkcje sumujące, takie jak COUNT()
czy SUM(), opatrzone były logicznymi nazwami kolumn. Etykiety takie
nazywane są aliasami kolumn; aliasy zwiększają czytelność zapytań i ich zbiorów
wynikowych.W dialekcie ANSI SQL alias kolumny umieszcza się bezpośrednio za
odpowiednią kolumną na liście pól polecenia SELECT. W przykładzie
ilustrującym zastosowanie klauzuli GROUP BY aliasem funkcji sumującej
COUNT() jest etykieta NumberWithName. Aliasy kolumn można definiować dla
dowolnych elementów zbioru wynikowego, zatem nie tylko dla funkcji
sumujących. W poniższym przykładzie alias LName zastępuje w zbiorze
wynikowym kolumnę LastName:
SELECT CUSTOMER.LastName LName, Count(*) NumberWithName
FROM CUSTOMER
GROUP BY CUSTOMER.LastName
Należy jednak pamiętać, że nie dopuszcza się stosowania aliasów w innych
częściach zapytania, np. w klauzulach WHERE lub GROUP BY. W tych
fragmentach polecenia SELECT należy stosować właściwe nazwy kolumn lub
wartości.
SQL Server oferuje alternatywną konstrukcję składniową, w której alias występuje
po lewej stronie nazwy kolumny i jest od niej oddzielony znakiem równości, tak
jak w poniższym przykładzie:
SELECT CUSTOMER.LastName NumberWithName=Count(*)
Rozdział 5 Praktyczne wprowadzenie do języka SQL 135
FROM CUSTOMER
GROUP BY CUSTOMER.LastName
Zapis taki nie jest dozwolony w dialektach Oracle i InterBase.
Aliasy tabel
Aby uniknąć wpisywania pełnej nazwy tabeli przy każdym odwołaniu do niej
w poleceniu SELECT, można zdefiniować krótszą nazwę zastępczą. W tym celu
należy w klauzuli FROM zdefiniować alias tabeli. Alias powinien znalezć się
bezpośrednio za właściwą nazwą tabeli. Ilustruje to poniższy przykład:
SELECT C.LastName, Count(*) NumberWithName
FROM CUSTOMER C
GROUP BY C.LastName
Należy nadmienić, że aliasu można używać już na liście pól polecenia SELECT,
mimo że definiowany jest dopiero w klauzuli FROM. Odwołania do obiektów
bazy danych są bowiem analizowane jeszcze przed wykonaniem zapytania.
Krótkie podsumowanie
Na tym kończy się pierwsza część praktycznego wprowadzenia do języka SQL.
Omówiono w niej tworzenie baz danych, tabel i wpisywanie danych.
Przedstawiono ponadto podstawowe mechanizmy konstruowania zapytań przy
użyciu polecenia SQL SELECT.
Dodatkowe komentarze
Informacje zawarte w tej sekcji stanowią uzupełnienie omówionych dotychczas
zagadnień. Znajdują się tutaj również dodatkowe informacje dla osób
rozpoczynających programowanie w języku SQL, pominięte w poprzedniej sekcji -
"Szybki start". Bardziej szczegółowe omówienie zaawansowanych elementów
języka SQL znalezć można w rozdziale 24.
Polecenie CONNECT
W większości dialektów SQL do zmiany bieżącego "kontekstu bazy danych" służy
polecenie CONNECT. Zmiana kontekstu polega na podłączeniu się do określonej
bazy danych, która będzie odtąd używana. Powyższe polecenie dostępne jest na
serwerach InterBase i Oracle. Poleceniem o działaniu odwrotnym do CONNECT
jest DISCONNECT.
W dialekcie SQL Server do zmiany kontekstu bazy danych służy polecenie USE.
W przeciwieństwie do CONNECT, USE nie pozwala na jednoczesny dostęp do
136 Część I
więcej niż jednej bazy danych. Dialekt SQL Server nie zawiera odpowiednika
polecenia DISCONNECT.
Polecenie UPDATE
Do zmiany danych zapisanych w tabeli służy polecenie SQL UPDATE. Działa ono
podobnie jak polecenie dBASE REPLACE ALL. Oto przykład użycia
omawianego polecenia:
UPDATE CUSTOMER
SET Zip='90210' WHERE City='Beverly Hills'
W powyższym przykładzie zmiana może - w zależności od danych - dotyczyć tylko
kilku lub jednego wiersza, za sprawą klauzuli WHERE. Można również
zrezygnować z klauzuli WHERE; zmiana dotyczyć będzie wówczas wszystkich
wierszy tabeli:
UPDATE CUSTOMER
SET State='CA'
Możliwe jest także zdefiniowanie nowej zawartości kolumny przy pomocy
zawartości innych kolumn w tej samej tabeli albo poprzedniej wartości
modyfikowanej kolumny:
UPDATE ORDERS
SET Amount=Amount+(Amount*.07)
Dialekt Transact-SQL, używany na serwerze SQL Server, zezwala na definiowanie
nowych wartości w tabeli przy pomocy wartości z innej tabeli. Oto przykład:
UPDATE ORDERS
SET Amount=Price
FROM ORDERS, ITEMS
WHERE ORDERS.ItemNumber=ITEMS.ItemNumber
Polecenie DELETE
Polecenie DELETE służy do usuwania wierszy z tabel. Aby usunąć wszystkie
wiersze z tabeli, należy użyć polecenia w postaci:
DELETE FROM CUSTOMER
Niektóre serwery oferują pojedyncze, szybciej działające polecenia - podobne do
polecenia ZAP, dostępnego w języku dBASE - służące do usuwania wszystkich
wierszy ze wskazanej tabeli. W przypadku serwera SQL Server odpowiednie
polecenie ma postać:
TRUNCATE TABLE CUSTOMER
Rozdział 5 Praktyczne wprowadzenie do języka SQL 137
Polecenie DELETE może zawierać klauzulę WHERE, określającą, które wiersze
mają być usunięte. Oto odpowiedni przykład:
DELETE FROM CUSTOMER
WHERE LastName<>'Doe'
COMMIT i ROLLBACK
Grupę zmian dokonanych w bazie danych określa się mianem transakcji. Polecenie
SQL COMMIT utrwala rezultaty wykonanej transakcji. Działanie COMMIT można
przyrównać do zapisania (save) bazy danych. Z kolei polecenie ROLLBACK
anuluje wszystkie zmiany, wprowadzone przez transakcję w bazie danych;
ROLLBACK działa jak funkcja undo. Oba powyższe polecenia wpływają wyłącznie
na zmiany dokonane od poprzedniej operacji COMMIT; nie można anulować
właśnie utrwalonych zmian.
Niektóre platformy systemowe, w tym SQL Server, wymagają, aby transakcja
została jawnie rozpoczęta; w przeciwnym wypadku nie będzie możliwe jej
utrwalenie ani anulowanie. Program WISQL, dostarczany z serwerem InterBase,
po uruchomieniu automatycznie rozpoczyna transakcję (wysyłając odpowiednik
polecenia InterBase SET TRANSACTION). Gdy użytkownik zamyka WISQL,
program pyta, czy wykonane czynności mają być utrwalone. Ponadto w dowolnej
chwili można utrwalić albo anulować zmiany, korzystając z opcji Commit Work
i Rollback Work, dostępnych w menu File.


Wyszukiwarka

Podobne podstrony:
06 rozdział 05 26pdmeq2uxr33udenjgfxnhbbmddcafwcxjosqa
06 Rozdział II Kwaterniony
06 Rozdzial 6
06 Rozdzial 4
06 Rozdział 04 Twierdzenie o funkcji uwikłanej i jego konsekwencje
06 2010 05 19
06 Rozdzial 22 23
06 Rozdział III
05 rozdział 05
ROZDZIAŁ 05 Dziedziczne nowotwory nerek
07 Rozdział 05 Całka funkcji dwóch zmiennych

więcej podobnych podstron