06 Rozdziae 05id 6394 Nieznany (2)

background image

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 znaleźć 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”.

background image

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

background image

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

background image

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

}

background image

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

background image

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)

background image

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.

background image

122

Część I

Na rysunku 5.2 przedstawiono zawartość tabeli ORDERS, wyświetloną po
wykonaniu polecenia

SELECT * FROM ORDERS

.

Na rysunku 5.3 przedstawiono zawartość tabeli ITEMS, wyświetloną po
wykonaniu polecenia

SELECT * FROM ITEMS

.

Rysunek 5.1.
Zawartość tabeli
CUSTOMER
wyświetlona
w programie
WISQL.

Rysunek 5.2.
Zawartość tabeli
ORDER
wyświetlona
w programie
WISQL.

background image

Rozdział 5 Praktyczne wprowadzenie do języka SQL

123

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.

Rysunek 5.3.
Zawartość tabeli
ITEMS
wyświetlona
w programie
WISQL.

background image

124

Część I

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.4.
Polecenie SELECT
z listą pól.

Rysunek 5.5.
Przykład użycia
funkcji UPPER
w poleceniu
SELECT.

background image

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.

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%'

Rysunek 5.6.
Ilustracja
zastosowania
klauzuli WHERE
w poleceniu
SELECT,

background image

126

Część I

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

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'

Rysunek 5.7.
Ilustracja
zastosowania
klauzuli WHERE
ze słowem LIKE
w poleceniu
SELECT,

Rysunek 5.8.
Zamówienia,
których wartość
przekracza 500
dolarów.

background image

Rozdział 5 Praktyczne wprowadzenie do języka SQL

127

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

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

Rysunek 59.
Ilustracja
zastosowania
klauzuli WHERE
ze słowem
BETWEEN.

Rysunek 5.10.
Tabela
CUSTOMER
złączona z tabelą
ORDERS.

background image

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

background image

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

.

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)

Rysunek 5.11.
Złączenie
zewnętrzne tabel
CUSTOMER
i ORDERS przy
użyciu polecenia
ANSI-SQL.

background image

130

Część I

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).

Rysunek 5.12.
Podzapytanie,
zawarte w klauzuli
WHERE innego
zapytania.

background image

Rozdział 5 Praktyczne wprowadzenie do języka SQL

131

Skąd wiadomo, które pola mają znaleźć 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

Rysunek 5.13
Zapytanie
wykorzystujące
klauzulę GROUP
BY

background image

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.

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).

Rysunek 5.14.
Wyniki poprawnie
skonstruowanego
zapytania

background image

Rozdział 5 Praktyczne wprowadzenie do języka SQL

133

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 znaleźć 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

Rysunek 5.15.
Zastosowanie
klauzuli HAVING
do ograniczenia
zbioru wierszy,
zwracanych przez
klauzulę GROUP
BY.

background image

134

Część I

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(*)

Rysunek 5.16.
Zastosowanie
klauzuli ORDER
BY.

background image

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 znaleźć 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 znaleźć 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

background image

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

background image

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 rozdzial 05 26pdmeq2uxr33ude Nieznany
06 Rozdzial III Nieznany
06 Rozdzial III Nieznany
pkt 06 ST id 360232 Nieznany
05 rozdzial 04 nzig3du5fdy5tkt5 Nieznany (2)
06 Stosowanie przepisow prawa i Nieznany
28 rozdzial 27 vmxgkzibmm3xcof4 Nieznany (2)
06 Sporzadzanie ciasta pszenneg Nieznany (3)
06 zarzadzanie czasemid 6452 Nieznany (2)
22 Rozdzial 21 KP4Q5YBIEV5DBSVC Nieznany (2)
09 08 Rozdzielnice budowlane RB Nieznany (2)
17 rozdzial 16 fq3zy7m2bu2oan6t Nieznany (2)
Kanicki Systemy Rozdzial 10 id Nieznany
29 rozdzial 28 ciw47mwstcqakqpq Nieznany
24 rozdzial 23 wjv3mksbkbdm37qy Nieznany
06 Przestrzeganie przepisow bez Nieznany (2)
82 Nw 06 Gietarka id 47395 Nieznany
29 rozdzial 28 w3cbrpnwzh762znr Nieznany (2)

więcej podobnych podstron