SQL język relacyjnych baz danych. Dialekt SQL firmy Microsoft Access 1. Idealny język baz danych Idealny język baz danych powinien umożliwiać użytkownikowi: tworzenie baz danych i struktur relacji, wykonywanie podstawowych zadań związanych z zarządzaniem danymi, jak: dodawanie nowych danych, modyfikacja istniejących danych, usuwanie istniejących danych, wykonywanie zarówno prostych, jak i skomplikowanych zapytań, powinien być językiem przenośnym, tzn. musi być zgodny z pewnym uznanym standardem, co umożliwi wykonywanie poleceń o tej samej strukturze i znaczeniu w różnych SZBD. Do opisu operacji na bazach danych stworzono specjalny język SQL (ang. Structured Query Language). Ponadto można powiedzieć, iż jest to database sub-language, tj. niepełny język obsługi baz danych (bez kontroli sterowania). Jego składnia i znaczenie jest określone odpowiednimi standardami międzynarodowymi (posiada on akceptację ANSI oraz standard ISO). W praktyce SQL stał się standardowym językiem zapytań dla relacyjnych baz danych. 2. Podstawowe cechy SQL jest językiem wysokiego poziomu (językiem czwartej generacji 4GL), opartym na słownictwie języka angielskiego, jego wyrażenia mają określoną strukturę, tym niemniej, jak większość nowoczesnych języków ma dość swobodny format, tzn. iż poszczególne fragmenty poleceń nie muszą być umieszczane w określanych miejscach, jest językiem deklaratywnym (nieproceduralnym), zorientowanym na wynik (użytkownik definiuje, co chce otrzymać, ale nie pisze jak), inaczej mówiąc, SQL nie potrzebuje zatem podawania przez użytkownika dokładnego sposobu dostępu do danych i sposobu przetwarzania danych, jest oparty na algebrze relacji, zawiera logikę trójwartościową, nie posiada instrukcji sterujących wykonywaniem programu, nie dopuszcza rekurencji, umożliwia definiowanie struktur danych, wyszukiwanie danych oraz operacje na danych, działa na zbiorach danych. 3. Historia SQL-a 1970: E.F.Codd, IBM Relacyjne bazy danych (dr Edgar F.Codd w czerwcowym numerze pisma Communications of the ACM przedstawił swój artykuł zatytułowany Relacyjny model danych dla dużych banków danych współużytkowanych, gdzie nakreślił główne idee stworzonego przez siebie modelu baz danych. 1974: Chamberlain, IBM, San Jose Structured English Query Language SEQUEL (ang. Structured English Query Language) (prototyp SQL). 1
1976-7: ulepszona wersja SEQUEL/2 (jednocześnie jej nazwa, ze względów prawnych, została zmieniona na SQL; tym niemniej, do dzisiaj niektórzy wymawiają nazwę SQL jako sikuel, choć oficjalna nazwa brzmi es-ku-el 1976: pierwszy system zarządzania relacyjną bazą danych (System R oparty na SQUEL/2 w firmie IBM). 1975: język SQUARE (ang. Specyfying Queries As Relational Expressions formułowanie zapytań w postaci wyrażeń relacyjnych rzeczywisty pierwowzór języka SQL pojawił się jeszcze przed systemem R 1977: ORACLE (Relational Software Inc.) pierwsza implementacja praktyczna (komercyjna), tj. pierwszy komercyjny serwer baz danych oparty na SQL. 1981: IBM SQL/DS. (SZBD), poprzednik DB/2 (1983), 1982: ANSI: RDL (Relational Data Language),. 1983: ISO definicja SQL. 1986: ANSI pierwszy standard SQL (SQL-86). 1987: ISO pierwszy standard SQL: ISO 9075: 1987 (E). 1989: ISO następny standard SQL: ISO 9076: 1989 (E) (SQL-89). 1992: ISO kolejna, wzbogacona wersja: ISO 9075: 1992 (E) (SQL 2). 1999: wdrożenie następnej wersji standardu SQL 3 (uwzględniał cechy obiektowe) Obecnie obowiązuje wersja standardu ANSI SQL:2011/2011 Aktualnie istnieje bardzo wiele swoistych implementacji opartych na SQL-u różnych firm i wciąż pojawiają się nowe. 4. Język SQL w aplikacjach bazodanowych Zasadniczo język SQL jest jedynym językiem rozumianym przez oprogramowanie zarządzające bazami danych. Ponieważ wszystkie instrukcje przekazywane do serwera są przekazywane w postaci wyrażeń języka SQL, a zatem nie ma znaczenia, czy narzędzie używane na stacji klienckiej ma prosty interfejs w postaci wiersza komend, czy jest to wysublimowany interfejs graficzny. Do komunikowania się za pomocą języka SQL można podejść dwojako: można włączać wyrażenia tego języka do modułów aplikacji lub budować te wyrażenia na podstawie informacji wprowadzanych przez użytkownika. 5. Komponenty języka SQL DDL (Data Definition Language) język definiowania struktur danych (CREATE) i kontroli dostępu, DQL (Data Query Language) język definiowania zapytań dla wyszukiwania danych (SELECT), DML (Data Manipulation Language) język operacji na danych (SELECT, INSERT, UPDATE, DELETE), tj. służący do wyszukiwania i modyfikowania danych, Instrukcje sterowania danymi kontrola uprawnień użytkowników (GRANT, REVOKE). Międzynarodowy standard języka SQL wyróżnia zasadniczo dwie główne części: DDL, DML. 2
6. Język SQL jako język 4G Języki czwartej generacji (4GL), takie jak np. SQL, są na ogół proste (w porównaniu z językami 3GL) i udostępniają mniejsza liczbę poleceń. Fakt, iż język SQL jest językiem czwartej generacji implikuje, iż opisuje on tylko żądanie zadania, a nie sposób jego wykonania. Ponadto języki 4GL izolują również użytkownika od wewnętrznych struktur danych i algorytmów. 7. Własności SQL-a jako języka 4G Poniższy schemat prezentuje porównanie możliwości języka SQL jako języka 4GL. 8. Ograniczenia języka SQL Podstawą języka SQL jest teoria zbiorów i w związku z tym jego przeznaczeniem jest manipulowanie zbiorami danych oraz przetwarzanie tych danych. SQL składa się ze stosunkowo niewielkiej liczby podstawowych poleceń, takich jak SELECT, INSERT, czy CREATE. Nazwa SQL jest myląca, gdyż w istocie nie jest to język strukturalny, a zdaniem niektórych specjalistów w ogóle nie jest to język programowania (tym niemniej w praktyce każde z powyżej przytoczonych poleceń wykonuje zadanie, którego zapis w języku strukturalnym mógłby zająć setki linii kodu. Jest to jeden z głównych powodów, dla którego działające na jego podstawie aktualnie dominują na rynku oprogramowania bazodanowego i są aktualnie tak powszechnie wykorzystywane). SQL nie jest językiem ogólnego przeznaczenia i nie umożliwia tworzenia różnego rodzaju algorytmów, program utworzony w języku SQL, składa się z serii jego instrukcji, to jednak nie może zawierać w sobie żadnych instrukcji warunkowych (dlatego w gruncie rzeczy nie należy mówić o kodzie języka SQL jako o programie), język SQL okazuje się także niewystarczający, np. w sytuacji, gdy zaistnieje potrzeba ochrony i szczególnego zabezpieczenia danych. 9. Rozszerzenia języka SQL Niejednokrotnie konieczne jest wykonanie pewnych operacji, które dla standardowego SQL są niemożliwe do wykonania. Aby sprostać sytuacjom, w których zawodzi SQL z powodu swoich ograniczeń, np. w sytuacji, gdy potrzebne są jakieś procedury, które zadaniem byłoby przetwarzanie kolejno wiersz po wierszu. 3
Niektórzy z producentów oprogramowania, aby sprostać sytuacjom, w których z racji swoich ograniczeń, SQL zawodzi, dołącza do sprzedawanych przez siebie rozwiązań różnego rodzaju rozszerzenia. Rozszerzenie języka jest zbiorem właściwości, które w pewien sposób zwiększają jego możliwości. Jednym z takich rozszerzeń języka SQL, jest np. oferowany przez firmę ORACLE w swoim systemie bazodanowym, język PL/SQL (Procedura Language Structured Query Language). Firma Microsoft w SZBD, jakim jest Microsoft Access, dołącza język proceduralny, a zatem język trzeciej generacji, jakim jest Visual Basic. 10. Formułowanie poleceń w języku SQL Zdanie (polecenie, zapytanie) języka SQL składa się z: słów zarezerwowanych (kluczowych), słów zdefiniowanych przez użytkownika. UWAGA. W wielu dialektach SQL wymagane jest zakończenie każdego zdania specjalnym znakiem zazwyczaj jest to średnik. Słowa kluczowe: są niezmienną częścią języka mają ustalone znaczenie, należy zapisywać dokładnie tak, jak wymaga tego składnia języka, nie wolno ich dzielić, przenosząc do następnego wiersza. Słowa zdefiniowane przez użytkownika: są tworzone przez użytkownika, zgodnie z pewnymi regułami synktatycznymi, są nazwami różnych obiektów bazy danych jak, np. tabele, pola, kwerendy, itp. 11. Formatowanie poleceń w języku SQL Chociaż SQL ma dość swobodny format, to jednak warto stosować pewien rodzaj formatowania poleceń tego języka, aby zwiększyć ich czytelność: każde polecenie powinno zaczynać się od nowego wiersza, początek każdej klauzuli (fragmentu zdania SQL pełniącego określone funkcje) powinien być dopasowany do początku innych klauzul, jeżeli klauzula składa się z kilku części, to powinny być one zapisane w oddzielnych wierszach, które powinny być odpowiednio wcięte, by odzwierciedlić zagłębianie kolejnych elementów klauzuli. Słowa kluczowe: są niezmienną częścią języka, mają ustalone znaczenie, należy zapisywać dokładnie tak, jak wymaga tego składnia języka, nie wolno ich dzielić, przenosząc do następnego wiersza. 12. Zapis składni poleceń języka SQL Notacja Backusa-Nura (BNF): 4
słowa zarezerwowane są pisane wielkimi literami w poleceniach należy zapisywać je dokładnie tak, jak w definicji, słowa definiowane przez użytkownika są pisane małymi literami, możliwość wyboru jednej z przedstawionych opcji jest oznaczona za pomocą pionowej kreski, np. a b c, elementy wymagane są umieszczane w nawiasach klamrowych, np. {a}, elementy opcjonalne (które mogą, ale nie muszą wystąpić) są umieszczane w nawiasach kwadratowych, np. [a], nawiasy okrągłe są używane do zaznaczenia możliwości powtórzenia elementu zero lub dowolną liczbę razy. 13. Instrukcja SELECT Podstawową, najczęściej używaną instrukcją języka SQL jest instrukcja SELECT, która służy do pobierania danych z jednej tabeli lub większej liczby tabel (ewentualnie zamiast tabel mogą to być inne kwerendy). Należy jednak podkreślić pewną ważną cechę relacyjnych baz danych. Niezależnie od liczby tabel i/lub kwerend oraz niezależnie od rodzaju operacji wykonywanych na zbiorach, zawsze jako wynik otrzymujemy wirtualną pojedynczą tabelę (tzw. dynamiczny zestaw wyników), którą dalej możemy przetwarzać. Podstawowa postać instrukcji SELECT SELECT lista_kolumn FROM lista_tabel; UWAGA. Każda instrukcja SELECT zawsze musi występować ze słowem kluczowym FROM, którego nigdy nie można opuścić. Na końcu zawsze musi się znaleźć średnik, który kończy instrukcję. Jeśli lista_kolumn składa się z jednej tabeli (kwerendy), to mamy do czynienia z zapytaniem jednotabelowym, zaś w pozostałych przypadkach z zapytaniem wielotabelowym. Pełna postać instrukcji SELECT SELECT [typ_zwracania] { * tabela.* [tabela.]pole1 [AS alias1] [, [tabela.]pole2 [AS alias2] [,...]]} FROM nazwa_tabeli(tabel) WHERE warunki_selekcji_wierszy GROUP BY lista_kolumn_grupujących HAVING warunki_selekcji_grup ORDER BY lista_kolumn_sortujących; gdzie: typ zwracania jeden z następujących parametrów: ALL, DISTINCT, DISTINCTROW lub TOP. Służą one do ograniczenia liczy zwracanych rekordów. Jeśli nie zostanie wpisane, domyślnie przyjmowana jest wartość ALL, * określa, że wszystkie pola są wybierane z tabeli bazowej, tabela nazwa tabeli, z której wybierane są rekordy, pole1, pole2, nazwy pól zawierających dane, które mają zostać pobrane. Jeśli zostanie dodane więcej niż jedno pole, dane z nich są pobierane według kolejności wpisania. alias1, alias2, nazwy, które mają pełnić rolę nagłówków kolumn zamiast oryginalnych nazw kolumn w tabeli, nazwa_tabeli(tabel) nazwa tabeli lub tabel zawierających dane, które mają zostać pobrane. 5
14. Instrukcja SELECT porządek klauzul Kolejność przetwarzania klauzul w instrukcji SELECT jest następująca: FROM określa tabelę (tabele i/lub kwerendy), z których będą pobierane dane, WHERE ogranicza wybrane wiersze tylko do tych, które spełniają podane warunki na liście ograniczeń, GROUP BY grupuje wiersze o tej samej wartości wskazanej kolumny (kolumn) znajdujących się na liście kolumn grupujących HAVING ogranicza wybór grup tylko do tych, które spełniają warunki ograniczeń znajdujące się na liście warunków selekcji grup, SELECT wskazuje, które kolumny powinny pojawić się w wyniku znajdują się one na liście przecinkowej tej klauzuli ORDER BY pozwala uporządkować wynik, tzn. posortować wyniki wg pól znajdujących się na liście kolumn sortujących. UWAGA. Porządku klauzul polecenia SELECT nie można zmieniać. Jedynymi klauzulami, które musi zawierać każde polecenie są SELECT i FROM; pozostałe mogą, ale nie muszą wystąpić w zapytaniu. 15. Przykłady jednotabelowych instrukcji SELECT PRZYKŁAD 1. Pobrać wszystkie pola z tabeli pracownicy I SPOSÓB SELECT nr, nazwisko, imię, [data ur], płeć, adres, [telefon domowy] ; II SPOSÓB wykorzystanie gwiazdki SELECT * ; PRZYKŁAD 2. Pobrać wszystkie nazwiska pracowników z tabeli pracownicy. SELECT nazwisko ; PRZYKŁAD 3. Wyświetlić te numery produktów, które przynajmniej raz zostały zakupione. SELECT DISTINCT [nr produktu] FROM [opisy zamówień]; 16. Sortowanie wyników klauzula ORDER BY Relacyjna baza danych w żaden sposób nie określa kolejności, w jakiej dane będą przechowywane(choć niektóre SZBD, w tym Microsoft Access mogą domyślnie sortować dane w oparciu o klucz główny). Do uporządkowania danych służy klauzula ORDER BY instrukcji SELECT, zawierająca listę przecinkową identyfikatorów kolumn, według których należy posortować wynik. Identyfikatorem kolumny może być jej nazwa lub numer pozycji na liście. Klauzula ORDER BY pozwala posortować dane w porządku rosnącym (ASC) ustawienie standardowe lub w porządku malejącym DESC, nawet wg kolumny która nie występuje w dynamicznym zestawie wyników. PRZYKŁAD 1. Posortować pracowników z tabeli pracownicy wg nazwisk i imion I SPOSÓB SELECT [nr pracownika], nazwisko, imię, [data ur], płeć, adres, [telefon domowy] 6
ORDER BY nazwisko, imię; II SPOSÓB SELECT [nr pracownika], nazwisko, imię, [data ur], płeć, adres, [telefon domowy] ORDER BY 2, 3; 17. Wybieranie wierszy klauzula WHERE Klauzula WHERE polecenia SELECT służy do ograniczania liczby wierszy wyświetlanych w dynamicznym zestawie wyników do tych, które spełniają zestaw warunków znajdujących się na liście ograniczeń tej klauzuli. Wyróżniamy pięć podstawowych typów warunków: wartość pusta warunek sprawdzający, czy w kolumnie jest wartość pusta (NULL); dopasowanie do wzorca dotyczy sprawdzenia, czy wartości pasują do podanego wzorca, porównanie warunek porównujący wartości jednego wyrażenia z wartością drugiego wyrażenia, sprawdzenie zakresu warunek dotyczący sprawdzenia, czy zadana wartość należy do wskazanego przedziału wartości, 18. Kryterium wartości pustej i niepustej PRZYKŁAD 1. Wyświetlić tych pracowników z tabeli pracownicy, którzy mają telefon domowy. SELECT [nr pracownika], nazwisko, imię, [data urodzenia], płeć, adres, [telefon domowy] WHERE [telefon domowy] IS NOT NULL; PRZYKŁAD 2. Wyświetlić tych pracowników z tabeli pracownicy, którzy nie mają telefonu domowego. SELECT [nr pracownika], nazwisko, imię, [data ur], płeć, adres, [telefon domowy] WHERE [telefon domowy] IS NULL; 19. Kryterium dopasowania do wzorca PRZYKŁAD 1. Wyświetlić wszystkich pracowników zamieszkałych w Warszawie. SELECT [nr pracownika], nazwisko, imię, [data urodzenia], płeć, adres, [telefon domowy] WHERE miasto = Warszawa ; PRZYKŁAD 2. Wyświetlić wszystkich pracowników, którzy nie mieszkają w Warszawie. SELECT [nr pracownika], nazwisko, imię, [data ur], płeć, adres, [telefon domowy] WHERE NOT miasto = "Warszawa"; W języku SQL firmy Microsoft Access występują dwa symbole wieloznaczne: * - symbol gwiazdki zastępuje dowolny ciąg znaków dowolnej długości,? zastępuje dowolny pojedynczy znak. 7
PRZYKŁAD 3. Wyświetlić wszystkich pracowników, których nazwisko kończy się na ski. SELECT [nr pracownika], nazwisko, imię WHERE nazwisko LIKE *ski ; 20. Kryterium porównania PRZYKŁAD 1. Wyświetlić tych pracowników, którzy urodzili się po 1 stycznia 1970 roku SELECT [nr pracownika], nazwisko, imię, [data ur] WHERE [data urodzenia] >= #1970/01/01#; PRZYKŁAD 2. Wyświetlić tych pracowników, którzy urodzili się w przedziale od 1 stycznia 1970 roku do 31 grudnia 1980 roku. I SPOSÓB SELECT [nr pracownika], nazwisko, imię, [data ur] WHERE [data ur] >= #1970/01/01# AND [data ur] <= #1980/12/31#; II SPOSÓB SELECT [nr pracownika], nazwisko, imię, [data ur] WHERE [data ur] BETWEEN #1970/01/01# AND #1980/12/31#; 21. Warunek selekcji przynależność do zbioru Operator IN przynależności do zbioru, sprawdza czy dana wartość jest jedną z wartości podanych na liście operatora, zaś zanegowana jego wersja NOT IN, czy dana wartość nie występuje na liście wartości. PRZYKŁAD 1. Wyświetlić tych pracowników, którzy mają na imię Adam lub Jan. I SPOSÓB II SPOSÓB SELECT [nr pracownika], nazwisko, imię SELECT [nr pracownika], nazwisko, imię WHERE imię IN ( Adam ; Jan ); WHERE imię = Adam OR imię = Jan ; Zasady obliczania wartości wyrażenia logicznego: wyrażenie oblicza się od lewej do prawej strony, w pierwszej kolejności obliczane są wyrażenia w nawiasach, NOT jest obliczane przed AND i OR, AND jest obliczane przed OR. UWAGA. Stosowanie nawiasów jest konieczne w przypadku takiego wrażenia logicznego, gdy zachodzi możliwość jego niejednoznacznej interpretacji. 8
22. Kwerendy wielotabelowe W celu uzyskania zapytania opartego na więcej niż jednej tabeli/kwerendzie, musimy wykonać operację złączenia. Kolumny, które porównujemy w celu dokonania połączenia tabel, nazywamy kolumnami złączenia. PRZYKŁAD 1. Wyświetlić klientów i złożone przez nich zamówienia. I SPOSÓB SELECT k.[kod klienta], k.[nazwa firmy], z.[nr zamówienia], z.[data zamówienia] FROM klienci AS k, zamówienia AS z WHERE k.[kod klienta] = z.[kod klienta]; II SPOSÓB SELECT k.[kod klienta], k.[nazwa firmy], z.[nr zamówienia], z.[data zamówienia] FROM klienci AS k INNER JOIN zamówienia AS z ON k.[kod klienta] = z.[kod klienta]; UWAGA. W przypadku braku połączenia tabel w zapytaniu wielotabelowym, jako wynik zostanie wygenerowany iloczyn kartezjański tabel, na których opiera się ta kwerenda. 23. Połączenia zewnętrzne Standardowo pomiędzy tabelami jest tworzone połączenie wewnętrzne, co oznacza, iż do dynamicznego zestawu wyników są wybierane te rekordy z obydwu połączonych tabel, które mają swoje odpowiedniki w drugiej tabeli, tzn. wartości kolumn łączących są równe w tych rekordach w obu tabelach. Aby wybrać rekordy, które nie mają swoich odpowiedników w drugiej tabeli, należy zastosować połączenie zewnętrzne pomiędzy tymi tabelami. PRZYKŁAD 1. Wyświetlić klientów i złożone przez nich zamówienia, przy czym wyświetlić nawet tych klientów, którzy nie złożyli żadnego zamówienia. SELECT k.[kod klienta], k.[nazwa firmy], z.[nr zamówienia], z.[data zamówienia] FROM klienci AS k LEFT JOIN zamówienia AS z ON k.[kod klienta] = z.[kod klienta]; W powyższym przykładzie zostało utworzone lewostronne połączenie zewnętrzne LEFT JOIN pomiędzy tabelami klienci i zamówienia. Innymi typami połączeń zewnętrznych są prawostronne połączenie zewnętrzne RIGHT JOIN i pełne połączenie zewnętrzne FULL JOIN. 24. Funkcje agregujące w języku SQL W języku SQL systemu bazodanowego Microsoft Access wyróżniamy następujące funkcje agregujące: COUNT zwraca liczbę wartości występujących w danej kolumnie, SUM zwraca sumę wartości występujących w danej kolumnie, AVG zwraca średnią wartości występujących w danej kolumnie, MIN zwraca najmniejszą wartość występującą w danej kolumnie, MIN zwraca największą wartość występującą w danej kolumnie, FIRST zwraca wartość z pierwszego rekordu zbioru wyników kwerendy, LAST zwraca wartość z ostatniego rekordu zbioru wyników kwerendy, VAR zwraca obliczoną wariancję zbioru wartości zawartych w określonej kolumnie. 9
Wymienione funkcje są obliczane na podstawie wartości jednej kolumny i zwracają w wyniku jedną wartość. Funkcje SUM i AVG można stosować jedynie do pól liczbowych, natomiast COUNT, MAX i MIN zarówno do liczbowych, jak i nieliczbowych. Wszystkie funkcje, oprócz COUNT(*), pomijają wartości puste i zwracają wynik obliczony jedynie dla pozostałych niepustych wartości. Natomiast funkcja COUNT(*) jest specjalnym zastosowaniem COUNT, która pozwala zliczać wszystkie wiersze tabeli, niezależnie od tego, czy są to wartości puste lub powtórzenia. 25. Przykłady zapytań dotyczących obliczeń na wszystkich rekordach tabeli. PRZYKŁAD 1. Obliczyć liczbę klientów zarejestrowanych w bazie SELECT COUNT([kod klienta]) AS liczba_klientow, FROM klienci; PRZYKŁAD 2. Obliczyć średnią cenę jednostkową wszystkich produktów niewycofanych aktualnie znajdujących się w magazynie. SELECT AVG([cena jednostkowa]) AS średnia_cena FROM produkty WHERE Wycofany = No; PRZYKŁAD 3. Obliczyć sumę wartości zamówień złożonych przez klientów krajowych. SELECT SUM(o.[cena jednostkowa]*o.[ilość]) AS wartość_zamówień FROM klienci AS k, zamówienia AS z, AS [opisy zamówień] o WHERE k.[kod klienta] = z.[kod klienta] AND z.[nr zamówienia] = o.[nr zamówienia] AND k.kraj = "Polska"; 26. Obliczenia w grupach rekordów klauzula GROUP BY Zapytanie zawierające klauzulę GROUP BY nazywamy kwerendą grupującą, gdyż w trakcie jego obliczania dane pobierane z tabeli (tabel) są dzielone na grupy i dla każdej takiej grupy jest generowany jeden wiersz obliczeń. Kolumny wyszczególnione na liście przecinkowej klauzuli GROUP BY nazywamy kolumnami grupowania. W przypadku zapytania grupującego: dla każdego elementu znajdującego się na liście przecinkowej klauzuli SELECT musi istnieć możliwość wyznaczenia jednoznacznie wartości w ramach grupy, na liście przecinkowej klauzuli SELECT mogą występować jedynie następujące elementy: nazwy kolumn grupowania, funkcje agregujące, stałe, wyrażenia zawierające kombinacje powyższych elementów. wszystkie nazwy kolumn znajdujące się na liście przecinkowej klauzuli SELECT muszą występować na liście przecinkowej klauzuli GROUP BY chyba, że nazwa kolumny jest używana jako argument funkcji agregującej (odwrotna własność nie musi być spełniona), gdy występuje klauzula WHERE, to jest ona wykonywana w pierwszej kolejności, tj. przed samym tworzeniem grup, które są tworzone tylko z rekordów spełniających warunki klauzuli WHERE. 10
27. Przykłady kwerend grupujących PRZYKŁAD 1. Obliczyć liczbę klientów z poszczególnych krajów zarejestrowanych w bazie SELECT kraj, COUNT([kod klienta]) AS liczba_klientow FROM klienci GROUP BY kraj ORDER BY 2; PRZYKŁAD 2. Obliczyć średnią cenę jednostkową wszystkich produktów niewycofanych aktualnie znajdujących się w magazynie z poszczególnych kategorii. SELECT [nazwa kategorii], AVG([cena jednostkowa]) AS średnia_cena FROM produkty, kategorie WHERE kategorie.[nr kategorii] = produkty.[nr kategorii] AND Wycofany = No GROUP BY [nazwa kategorii] ORDER BY 2; 28. Wybór grup klauzula HAVING W przypadku zastosowania klauzuli HAVING w kwerendzie grupującej, w dynamicznym zestawie wyników zostaną wyświetlone tylko te grupy (wraz ze swoimi obliczeniami), które spełniają warunki ograniczeń umieszczone na liście przecinkowej tej klauzuli. Jaka jest różnica pomiędzy warunkami klauzuli WHERE i HAVING? klauzula WHERE pozwala przetestować oddzielnie każdy rekord i wybrać tylko te z nich, które spełniają warunki ograniczeń umieszczone na liście przecinkowej tej klauzuli warunki ograniczeń tej klauzuli działają przed wykonaniem obliczeń W praktyce, w klauzuli tej nie wolno używać warunków w postaci wyrażeń z funkcjami agregującymi warunki takie muszą zostać przeniesione do klauzuli HAVING klauzula HAVING służy zaś do wyboru grup zostaną wybrane tylko te z nich, które spełniają warunki umieszczone na liście przecinkowej tej klauzuli warunki tej klauzuli działają po wykonaniu obliczeń w praktyce, warunek wyszukiwania tej klauzuli zawsze zawiera wyrażenie z przynajmniej jedną funkcją agregującą, gdyż w przeciwnym razie warunek ten mógłby zostać przeniesiony do klauzuli WHERE i zastosowany do każdego wiersza oddzielnie 29. Przykłady zastosowania klauzuli HAVING PRZYKŁAD 1. Wyświetlić liczbę klientów z poszczególnych krajów zarejestrowanych w bazie, przy czym ograniczyć się do wyświetlenia tych krajów, z których zarejestrowanych jest ponad 5 klientów. SELECT kraj, COUNT([kod klienta]) AS liczba_klientow FROM klienci GROUP BY kraj HAVING COUNT([kod klienta]) > 5 ORDER BY 2; 11
PRZYKŁAD 2. Obliczyć średnią cenę jednostkową wszystkich produktów niewycofanych aktualnie znajdujących się w magazynie z poszczególnych kategorii, przy czym wyświetlić te kategorie, dla których obliczona średnia jest większa niż 40 zł. SELECT [nazwa kategorii], AVG([cena jednostkowa]) AS średnia_cena FROM produkty, kategorie WHERE kategorie.[nr kategorii] = produkty.[nr kategorii] AND Wycofany = No GROUP BY [nazwa kategorii] HAVING AVG([cena jednostkowa]) > 40 ORDER BY 2; 30. Kwerendy krzyżowe Kwerendy krzyżowe wyświetlają wyniki kwerendy agregującej w postaci przypominającej arkusz kalkulacyjny. Kwerenda zaczyna się od słowa kluczowego TRANSFORM, w którym umieszczamy pole, które dotyczy obliczeń z funkcja agregującą, nagłówek kolumny umieszczamy na końcu kwerendy po słowie kluczowym PIVOT nie można stosować tu aliasów, podobnie jak w klauzuli GROUP BY, gdzie umieszczamy wszystkie nagłówki wierszy. Przykład. Wyświetlić liczbę zamówień obsłużonych przez poszczególnych pracowników w poszczególnych miesiącach roku. TRANSFORM Count(z.[Nr zamówienia]) AS [Liczba zamówień] SELECT p.[nr pracownika], p.[nazwisko] & " " & p.[imię] AS pracownik, Count(z.[Nr zamówienia]) AS liczba_zam AS p INNER JOIN zamówienia AS z ON p.[nr pracownika] = z.[nr pracownika] GROUP BY p.[nr pracownika], p.[nazwisko] & " " & p.[imię] ORDER BY 3 DESC PIVOT Month(z.[Data zamówienia]); 31. Kwerendy zagnieżdżone W przeciwieństwie do warunków statycznych, tj. warunków umieszczanych w klauzuli WHERE i ewentualnie HAVING, warunki dynamiczne charakteryzują się możliwością zmian wartości przy kolejnych uruchomieniach kwerendy. Realizuje się je poprzez umieszczanie (zagnieżdżanie) zapytania w drugim zapytaniu, które właśnie tworzy nam taki warunek dynamiczny. Takie zapytanie nazywamy podzapytaniem, zaś zapytanie określamy mianem zapytaniem zagnieżdżonym. Wśród tego rodzaju zapytań z podzapytaniami wyróżniamy: podzapytania nieskorelowane, podzapytania skorelowane. 32. Podzapytania nieskorelowane wykonuje się tylko raz, przed wykonaniem zapytania głównego, jego wynik nie zależy od zapytania głównego, 12
zwraca zawsze tylko jedną wartość, działa w ten sposób, iż po swoim wykonaniu wstawia swoje wyniki do warunków klauzuli WHERE zapytania głównego. Przykład 1. Jako przykład zastosowania kwerendy nieskorelowanej, rozważymy polecenie wybrania wszystkich towarów, których cena jednostkowa przekracza wartość średnią ceny jednostkowej obliczonej ze wszystkich produktów znajdujących się w magazynie (w bazie danych). I SPOSÓB bez użycia zapytania z podzapytaniem nieskorelowanym Ponieważ średnia cena jednostkowa wszystkich towarów, których dane są aktualnie przechowywane w tabeli produkty nie jest nam z góry znana (może zresztą w każdej chwili ulec zmianie pod dopisaniu danych nowego towaru do tabeli produkty lub usunięciu z niej już tam wpisanego wcześniej), musimy utworzyć zapytanie, które ją obliczy: SELECT AVG([cena jednostkowa]) FROM produkty; Jego wynikiem będzie obliczona średnia cena jednostkowa wszystkich produktów, których dane są aktualnie przechowywane w tabeli produkty. AVG(CENA) ------------------- 10,06 SELECT [nr produktu], [nazwa produktu], [cena jednostkowa] FROM produkty WHERE [cena jednostkowa] > 10,06 ORDER BY [cena jednostkowa] DESC; II SPOSÓB z użyciem zapytania z podzapytaniem nieskorelowanym SELECT [nr produktu], [nazwa produktu], [cena jednostkowa] FROM produkty WHERE [cena jednostkowa] > (SELECT AVG([cena jednostkowa]) FROM prdukty) ORDER BY [cena jednostkowa] DESC; Przykład 2. Wyświetlić wszystkie produkty w sklepie o największej cenie. I SPOSÓB z wykorzystaniem kwerendy zagnieżdżonej nieskorelowanej SELECT [nr produktu], [nazwa produktu], [cena jednostkowa] FROM produkty WHERE [cena jednostkowa] = (SELECT MAX([cena jednostkowa]) FROM produkty); II SPOSÓB Język QBE umożliwia wykonanie tej kwerendy także w następujący sposób: SELECT TOP 1 [nr produktu], [nazwa produktu], [cena jednostkowa] FROM produkty ORDER BY [cena jednostkowa] DESC; 13
Graficzne przedstawienie zasady działania zapytania z podzapytaniem nieskorelowanym: SELECT [nazwa produktu], [cena jednostkowa] FROM produkty WHERE [cena jednostkowa] > (SELECT AVG([cena jednostkowa]) FROM produkty) ORDER BY [cena jednostkowa] DESC; zapytanie główne podzapytanie uruchamiane na końcu uruchamiane jako pierwsze Jak wynika choćby z przytoczonego przykładu, podzapytania nieskorelowane muszą spełniać dwa warunki: muszą być ujęte w nawiasy, muszą występować po prawej stronie wyrażenia warunkowego. Uwaga. Ważne jest, aby w zapytaniu z podzapytaniem nieskorelowanym, podzapytanie zwracało tylko jedną wartość. W przytoczonym powyżej przykładzie zapytania z podzapytaniem nieskorelowanym, zarówno zapytanie główne, jak i samo podzapytanie oparte były na tej samej tabeli. Tym niemniej możliwe jest, aby tabele, na których są one oparte były różne. 33. Podzapytania skorelowane wykonuje się tyle razy ile razy jest uruchamiane zapytanie główne, w jego klauzuli WHERE znajduje się przynajmniej jeden element (nazwa kolumny) z zapytania głównego dlatego jego wynik zależy od zapytania głównego, zwraca więcej niż jedną wartość ale w każdym wywołaniu powinno zwracać w najprostszym przypadku zawsze jedną wartość, jest wywoływane po uprzednim wywołaniu zapytania głównego po swoim wykonaniu wstawia swoje wyniki do warunków klauzuli WHERE zapytania głównego. Przykład. Interesuje nas wyświetlenie w każdej kategorii towarów, nazwy towaru o największej cenie. SELECT k.[nazwa kategorii], p.[nr produktu], p.[nazwa produktu], p.[cena jednostkowa] FROM produkty AS p INNER JOIN kategorie AS k ON p.[nr kategorii] = k.[nr kategorii] WHERE p.[cena jednostkowa] = (SELECT MAX(p1.[cena jednostkowa]) FROM produkty AS p1 INNER JOIN kategorie AS k1 ON p1.[nr kategorii] = k1.[nr kategorii] WHERE k1.[nazwa kategorii] = k.[nazwa kategorii]) warunek korelacji ORDER BY k.[nazwa kategorii]; Uwaga. Podzapytanie skorelowane posiada specyficzną strukturę. Otóż konieczne jest oznaczenie wszystkich pól należących do zapytania głównego i wszystkich pól należących do podzapytania, szczególnie w przypadku, gdy tabele, na których oparte jest zapytanie główne i podzapytanie, są takie same (tak, jak ma to miejsce w rozważonym przykładzie). W tym celu należy oznaczyć tabele występujące w zapytaniu głównym aliasami, a tabele w podzapytaniu również aliasami, ale takimi, które nie zostały wykorzystane w zapytaniu głównym. 14
34. Zagnieżdżanie podzapytań W języku SQL istnieje możliwość dalszego zagnieżdżania podzapytań. Jedną z takich możliwości zagnieżdżania jest możliwość osadzania zapytania w podzapytaniu, tworząc w ten sposób podzapytanie podzaptania. W takim przypadku mamy zatem do czynienia z sytuacją, w której zapytanie główne zależy od wyników podzapytania, które z kolei zależy od jego własnego podzapytania. Takie zagnieżdżanie nie musi być zresztą ograniczone tylko do trzech poziomów. Przykład. SELECT a.[nr produktu], a.[nazwa produktu], a.[cena jednostkowa] FROM produkty AS a WHERE a.[cena jednostkowa] > (SELECT AVG(b.[cena jednostkowa]) FROM produkty AS b WHERE [cena jednostkowa] > (SELECT MAX(c.[cena jednostkowa])/2 FROM produkty AS c, [opisy zamówień] AS d, zamówienia AS e WHERE c.[nr produktu] = d.[nr produktu] AND e.[nr zamówienia] = d.[nr zamówienia] AND MONTH([data zamówienia]) IN (1, 4, 9))) ORDER BY a.[cena jednostkowa] DESC; Uwaga. Choć jest dozwolonego zagnieżdżanie podzapytań i tworzenie zapytań z wieloma poziomami podzapytań, to jednak należy ustrzegać się pisania zapytań ze zbyt wieloma poziomami rozgałęzień podzaptań i wieloma poziomami zagnieżdżeń. Wynika to choćby z konsekwencji ich poprawiania w razie jakiegoś błędu przez osobę, która ich nie tworzyła, a i samemu ich projektantowi po dłuższym odstępie czasu może przyjść z trudnością zrozumienie ich konstrukcji i zasady działania. Dla podzapytań obowiązują zatem następujące zasady: w podzapytaniach nie wolno używać klauzuli ORDER BY (chociaż wolno jej używać w najbardziej zewnętrznym zapytaniu, lista przecinkowa klauzuli SELECT podzapytania może składać się tylko z pojedynczej nazwy kolumny lub pojedynczego wyrażenia, domyślnie, nazwy kolumn w podzapytaniu odnoszą się do nazwy tabeli z klauzuli FROM podzapytania. Do kolumn tabeli z klauzuli FROM zapytania zewnętrznego można odwoływać się, poprzedzając nazwę kolumny nazwą tabeli zapytania zewnętrznego, jeżeli podzapytanie jest jednym z dwóch argumentów, których dotyczy porównanie, to musi występować po prawej stronie porównania. 35. Polecenia DML Oprócz polecenia SELECT, wśród poleceń DML wyróżniamy jeszcze polecenia: INSERT wprowadzanie danych do tabel, UPDATE aktualizowanie danych w tabelach, DELETE usuwanie danych z tabel. 15
Przykład 1. Do tabeli klienci wprowadzić jeden rekord danych INSERT INTO klienci ( [kod klienta], [nazwa firmy], adres, miasto, kraj, telefon ) VALUES ("MRTS", "Mar-Trans", "Poprzeczna 5", "Koszalin", "Polska", "091 89-21-09"); UWAGA. W przypadku, gdy do tabeli nie wprowadzamy danych do wszystkich pól, po nazwie tabeli w poleceniu INSERT wymieniamy w nawiasach nazwy tych pól, do których chcemy wprowadzić dane. Jeśli wprowadzamy dane od wszystkich pól, można opuścić nazwy pól. Jeśli nie wymienimy nazw pól po nazwie tabeli w poleceniu INSERT i nie wprowadzamy danych do wszystkich pól tabeli, to w klauzuli VALUES w miejscu pola, do którego nie wprowadzamy danych, wpisujemy NULL. Przykład 2. Do tabeli klienci wprowadzono jeden rekord danych w Przykładzie 1. Pomyłkowo wprowadzono adres Poprzeczna 5, a powinno być Poprzeczna 15. Należy skorygować tę pomyłkę za pomocą instrukcji aktualizującej. UPDATE klienci SET adres = "Poprzeczna 15" WHERE [kod klienta] = "MRTS"; UWAGA. W przypadku, gdy w poleceniu UPDATE zostanie pominięta klauzula WHERE lub warunek tej klauzuli jest spełniony dla wszystkich rekordów, to wtedy po uruchomieniu kwerendy wartość w podanym polu zostanie zaktualizowana we wszystkich rekordach. Przykład 3. Do tabeli klienci wprowadzono pomyłkowo klienta o kodzie MRTS. Należy usunąć tego klienta za pomocą instrukcji DELETE. DELETE FROM klienci WHERE [kod klienta] = "MRTS"; Uwaga. W przypadku, gdy w poleceniu DELETE zostanie pominięta klauzula WHERE lub warunek tej klauzuli jest spełniony dla wszystkich rekordów, to wtedy po uruchomieniu kwerendy zostaną bezpowrotnie usunięte wszystkie rekordy z tabeli. 36. Kwerendy SQL W Microsoft Access istnieją tzw. kwerendy SQL, które mogą być wykorzystane do komunikowania się z wewnętrznym serwerem SQL: kwerenda aktualizująca łączy pola pochodzące z jednej lub kilku tabel bądź kwerend w jednym polu lub kolumnie trzeciej tabeli, kwerenda definiująca dane tworzy, usuwa lub zmienia tabele w bieżącej bazie danych, a także tworzy indeksy, kwerenda przekazująca działa bezpośrednio na bazach danych ODBC, korzystając z poleceń zawartych w słowniku tego serwera podkwerenda umieszcza instrukcję SQL SELECT wewnątrz innej kwerendy wybierającej lub funkcjonalnej (jest stosowana w wierszu Kryteria siatki projektowej kwerendy). Uwaga. Wszystkie kwerendy SQL muszą być konstruowane w kodzie SQL i mogą być uruchamiane z poziomu makra lub można je osadzać w procedurach języka Visual Basic. 16
37. Kwerendy SQL - kwerendy definiujące dane Kwerendę definiującą można wykorzystać do: utworzenia nowej tabeli, modyfikacji istniejącej tabeli, usunięcia istniejącej tabeli, utworzenia indeksu. W Microsoft Access mamy do dyspozycji cztery instrukcje definicji danych, jakie możemy użyć w kwerendzie definiującej dane: CREATE TABLE tworzy nową tabelę, ALTER TABLE dodaje nowe pole lub ograniczenie do istniejącej tabeli albo usuwa pole lub ograniczenie, DROP usuwa tabele z bazy danych albo indeks z tabeli, CREATE INDEX tworzy indeks dla jednego lub kilku pól w istniejącej tabeli. 38. Polecenie CREATE TABLE Aparat bazy danych programu Microsoft Access nie obsługuje stosowania instrukcji CREATE TABLE ani żadnych innych instrukcji DDL z bazami danych innymi niż bazy programu Microsoft Access. Polecenie CREATE TABLE służy do tworzenia nowej tabeli, a jego składnia jest następująca: CREATE [TEMPORARY] TABLE nazwa_tabeli (typ_pola1 [(rozmiar)] [NOT NULL] [indeks1] [, typ pola2 [(rozmiar)] [NOT NULL] [indeks2] [, typ polan [(rozmiar)] [NOT NULL] [indeksn] [, CONSTRAINT indeks_wielopolowy [,...]]); Znaczenie poszczególnych elementów składni polecenia CREATE TABLE: Nazwa elementu składni nazwa_tabeli pole1, pole2 typ rozmiar indeks1, indeks2 indeks_wielopolowy Opis Nazwa tabeli, która ma zostać utworzona. Nazwa pola lub pól, jakie mają zostać utworzone w nowej tabeli. Należy utworzyć przynajmniej jedno pole. Typ danych pola w nowej tabeli. Rozmiar pola wyrażony w znakach (tylko pola zawierające dane tekstowe i binarne). Klauzula CONSTRAINT określająca indeks jednopolowy. Klauzula CONSTRAINT określająca indeks wielopolowy. 17
39. Klauzula CONSTRAINT Za pomocą klauzuli CONSTRAINT w instrukcjach CREATE TABLE i ALTER TABLE można tworzyć i usuwać ograniczenia. Istnieją dwa typy klauzul CONSTRAINT: jeden z nich pozwala utworzyć ograniczenie dla jednego pola, drugi z nich pozwala tworzyć ograniczenie dla większej liczby pól. Typy ograniczeń, jakie możemy nakładać na tabelę przy pomocy klauzuli CONSTRAINT w instrukcji CREATE TABLE: PRIMARY KEY wyznacza pole (lub grupę pól), które tworzy klucz podstawowy, UNIQUE określa klucz unikatowy, NOT NULL wykluczenie wartości NULL w określonym polu, FOREIGN KEY określa pole klucza obcego w tabeli. 40. Polecenie CREATE TABLE - przykłady Przykład 1. Utworzyć za pomocą polecenia CREATE TABLE tabelę osoby z polami: nr_osoby, nazwisko, imie, pesel, data_ur, plec, przy czym nr_osoby - klucz główny. I SPOSÓB II SPOSÓB CREATE TABLE osoby CREATE TABLE osoby (nr_osoby TEXT(5) PRIMARY KEY, (nr_osoby TEXT(5), nazwisko STRING(25) NOT NULL, nazwisko STRING(25) NOT NULL, imie TEXT(15) NOT NULL, imie STRING(15) NOT NULL, pesel TEXT(11), pesel TEXT(11), data_ur DATETIME, data_ur DATETIME, plec BIT); plec BIT, CONSTRAINT osoby_pk PRIMARY KEY(nr_osoby)); Przykład 2. Utworzyć za pomocą polecenia CREATE TABLE tabelę osoby z polami: pesel, nazwisko, imie, data_ur, plec, przy czym nrpensji - klucz główny. CREATE TABLE pensje (nrpensji INTEGER PRIMARY KEY, kodosoby TEXT(11), datapensji DATE, CONSTRAINT fk_pensje_osoby FOREIGN KEY (kodosoby) REFERENCES osoby(nr_osoby)); 41. Instrukcja ALTER TABLE Polecenie ALTER TABLE służy do: dodania nowego pola do tabeli przy użyciu klauzuli ADD COLUMN, 18
zmieniać rozmiar pola za pomocą klauzuli ALTER COLUMN, usunięcia pola z tabeli przy użyciu klauzuli DROP COLUMN, dodania lub usunięcia indeksu przy wykorzystaniu klauzuli CONSTRAINT. Składnia instrukcji ALTER TABLE ALTER TABLE tabela {ADD {COLUMN typ pola[(rozmiar)] [NOT NULL] [CONSTRAINT indeks] ALTER COLUMN typ pola[(rozmiar)] CONSTRAINT indeks_wielopolowy} DROP {COLUMN pole I CONSTRAINT nazwa_indeksu} } UWAGA. Za pomocą pojedynczego polecenia ALTER TABLE nie można dodać lub usunąć więcej niż jednego pola lub indeksu. 42. Instrukcja ALTER TABLE - przykłady Przykład 1. Należy dodać do tabeli osoby kolumnę adres długości 30 znaków. ALTER TABLE osoby ADD COLUMN adres TEXT(30); Przykład 2. Należy dodać do tabeli osoby kolumnę adres długości 30 znaków, przy czym pole to nie może zawierać wartości pustej. ALTER TABLE osoby ADD COLUMN adres TEXT(30) NOT NULL; Przykład 3. Należy ustawić pole istniejące pole adres w tabeli osoby, aby nie mogło zawierać wartości pustej. ALTER TABLE osoby ADD CONSTRAINT adres NOT NULL; Przykład 4. Usunąć z tabeli osoby kolumnę adres. ALTER TABLE osoby DROP COLUMN adres; Przykład 5. Zmienić w tabeli osoby rozmiar kolumny adres na 35 znaków. ALTER TABLE osoby ALTER COLUMN adres TEXT(35); 43. Instrukcja CREATE INDEX Polecenie CREATE INDEX służy do tworzenia indeksu dla tabeli: Składnia instrukcji CREATE INDEX CREATE [ UNIQUE ] INDEX indeks ON tabela (pole [ASC DESC][, pole [ASC DESC],...]) Przykład 1. Należy utworzyć w tabeli osoby indeks nazwiska dla pola nazwisko. CREATE INDEX nazwiska ON osoby ([nazwisko]); Przykład 2. Należy utworzyć do tabeli osoby indeks unikatowy pesele dla pola pesel. CREATE UNIQUE INDEX pesele ON osoby ([pesel]); Przykład 3. Należy usunąć w tabeli osoby indeks nazwiska dla pola nazwisko. DROP INDEX nazwiska ON osoby; 19