Dysponujemy bazą danych SQLite3 zapisaną w pliku uczniowie2.db. Ćwiczenia wykonamy w programie SQLiteStudio, ale można do tego celu użyć wiersza poleceń bazy SQLite3. Informacje na temat tych narzędzi zawarte zostały w materiale Definiowanie schematu bazy danych w języku SQL, etap IIPkXbedRKMDefiniowanie schematu bazy danych w języku SQL, etap II. Zapytania można również wykonać za pomocą skryptu języka Python, który omówiono w materiale Instrukcje wyszukiwania w języku SQL, etap IIIPkQh27XjUInstrukcje wyszukiwania w języku SQL, etap III.
Po uruchomieniu programu SQLiteStudio wybierz polecenie Bazy danych | Dodaj bazę danych i wskaż położenie pliku uczniowie2.db. Następnie połącz się z bazą, dwukrotnie klikając nazwę bazy w panelu Bazy danych.
Program SQLiteStudio ułatwia poznanie schematu bazy danych, udostępniając wszystkie informacje potrzebne do poznania tabel i łączących je relacji. Po dwukrotnym kliknięciu wybranej tabeli w panelu po lewej stronie, w zakładce Struktura zobaczymy nazwy i typy danych pól zawartych w tabeli.
R1XlKxJZPJMXW
Podgląd struktury tabeli w programie SQLiteStudio. Widoczne jest okno dialogowe. W kolumnie Bazy danych widoczna jest struktura bazy uczniowie2 (SQLLite 3). Tabele (3): Oceny, Przedmioty, Uczniowie. W strukturze widoczny jest jeszcze folder Widoki. Spośród zakładek okna dialogowego wyświetlona jest zakładka Struktura. Tabela zawiera 8 kolumn i 4 wiersze. Są to kolejno: Nazwa, typ danych, Klucz główny, Klucz obcy, Wartości unikalne, Warunek i Niepsute.
Podgląd struktury tabeli w programie SQLiteStudio.
Źródło: Contentplus.pl sp. z o.o., licencja: CC BY-SA 3.0.
Jeżeli klikniemy zakładkę DDL, zobaczymy polecenie SQL, które zostało użyte do utworzenia danej tabeli i ewentualnych powiązań.
Rqp8BrJSzBKnG
Podgląd polecenia SQL DDL, które posłużyło do utworzenia tabeli w programie SQLiteStudio. W kolumnie Bazy danych widoczna jest struktura bazy uczniowie 2. Spośród zakładek głównego okna wyświetlono zakładkę DDL. Widoczny jest zapis. Linia 1 CREATE TABLE oceny (. Linia 2 id_ucz INTEGER NOT NULL, Linia 3 ocena DECIMAL (2, 1) NOT NULL, Linia 4 data DATE NOT NULL, Linia 5 id_prz INTEGER NOT NULL, Linia 6 FOREIGN KEY ( Linia 7 id_ucz Linia 8 ( Linia 9 ( PREFERENCES uczniowie (id_ucz), Linia 10 FOREIGN KEY ( Linia 11 id_prz Linia 12 ) Linia 13 REFERENCES przedmioty (id_prz) Linia 14 );
Podgląd polecenia SQL DDL, które posłużyło do utworzenia tabeli w programie SQLiteStudio.
Źródło: Contentplus.pl sp. z o.o., licencja: CC BY-SA 3.0.
Ćwiczenie 1
Przeanalizuj schemat bazy, korzystając z informacji o tabelach widocznych na zakładkach Struktura i/lub DDL.
Polecenie DDL tworzące tabelę uczniowie:
Linia 1. CREATE TABLE uczniowie otwórz nawias okrągły.
Linia 2. id podkreślnik ucz INTEGER PRIMARY KEY AUTOINCREMENT przecinek.
Linia 3. nazwisko VARCHAR otwórz nawias okrągły 30 zamknij nawias okrągły NOT NULL przecinek.
Linia 4. imie VARCHAR otwórz nawias okrągły 30 zamknij nawias okrągły NOT NULL przecinek.
Linia 5. ulica VARCHAR otwórz nawias okrągły 50 zamknij nawias okrągły NOT NULL przecinek.
Linia 6. nr podkreślnik domu VARCHAR otwórz nawias okrągły 25 zamknij nawias okrągły NOT NULL przecinek.
Linia 7. klasa VARCHAR otwórz nawias okrągły 2 zamknij nawias okrągły NOT NULL.
Linia 8. zamknij nawias okrągły średnik.
CREATE TABLE uczniowie (
id_ucz INTEGER PRIMARY KEY AUTOINCREMENT,
nazwisko VARCHAR (30) NOT NULL,
imie VARCHAR (30) NOT NULL,
ulica VARCHAR (50) NOT NULL,
nr_domu VARCHAR (25) NOT NULL,
klasa VARCHAR (2) NOT NULL
);
nazwa, naucz_nazwa, naucz_imie – VARCHAR, dane tekstowe.
Polecenie DDL tworzące tabelę oceny:
Linia 1. CREATE TABLE oceny otwórz nawias okrągły.
Linia 2. id podkreślnik ucz INTEGER NOT NULL przecinek.
Linia 3. ocena DECIMAL otwórz nawias okrągły 2 przecinek 1 zamknij nawias okrągły NOT NULL przecinek.
Linia 4. data DATE NOT NULL przecinek.
Linia 5. id podkreślnik prz INTEGER NOT NULL przecinek.
Linia 6. FOREIGN KEY otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły REFERENCES uczniowie otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły przecinek.
Linia 7. FOREIGN KEY otwórz nawias okrągły id podkreślnik prz zamknij nawias okrągły REFERENCES przedmioty otwórz nawias okrągły id podkreślnik prz zamknij nawias okrągły.
Linia 8. zamknij nawias okrągły średnik.
CREATE TABLE oceny (
id_ucz INTEGER NOT NULL,
ocena DECIMAL (2, 1) NOT NULL,
data DATE NOT NULL,
id_prz INTEGER NOT NULL,
FOREIGN KEY (id_ucz) REFERENCES uczniowie (id_ucz),
FOREIGN KEY (id_prz) REFERENCES przedmioty (id_prz)
);
W tabeli oceny występują pola:
id_ucz, id_prz – INTEGER, klucze obce, identyfikatory ucznia i przedmiotu,
ocena – DECIMAL, pole zawierające oceny,
data – DATE, pole przechowujące datę wystawienia oceny w formacie ISO8601 „YYYY‑MM‑DD”.
Tabele uczniowie i przedmioty łączy relacja wiele‑do‑wielu definiowana przez relacje jeden‑do‑wielu każdej z tych tabel z tabelą oceny, w której zgromadzono informacje o ocenach każdego ucznia z różnych przedmiotów.
RZ7c1IlEUtAXo
Zrzut ekranu z programu LibreOffice Base. Przedstawia relacje między trzema tabelami. Tabela uczniowie zawiera pola id_ucz, nazwisko, imie, ulica, dom, id_klasy. Tabela oceny zawiera pola: id, id_ucz, icena, data, id_przedm. Tabela przedmioty zawiera id_przedm, nazwa_przedm, nazwisko_naucz, imie_naucz. Pola id_ucz tabel uczniowie oraz oceny połączono linią. Nad linią przy tabeli uczniowie jest cyfra 1, a przy tabeli oceny litera n. Pola id_przed tabel oceny oraz przedmioty połączono linią. Nad linią przy tabeli oceny jest litera n, a przy tabeli oceny cyfra 1.
Widok tabel, pól i relacji w bazie uczniowie2.
Źródło: Contentplus.pl sp. z o.o., licencja: CC BY-SA 3.0.
Grupowanie danych
Spróbujmy przeanalizować niektóre dane dotyczące uczniów zapisane w bazie danych.
Polecenie 1
Napiszmy kwerendę, która wyświetli liczbę uczniów mieszkających na tej samej ulicy.
Zacznijmy od zapytania zliczającego uczniów:
Linia 1. SELECT COUNT otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły AS liczba podkreślnik uczniow.
Linia 2. FROM uczniowie średnik.
SELECT COUNT(id_ucz) AS liczba_uczniow
FROM uczniowie;
Dzięki funkcji COUNT() dowiemy się, że w bazie zapisano dane 414 uczniów.
Jeśli jednak chcemy zobaczyć, ilu uczniów mieszka na tej samej ulicy, powinniśmy pogrupować uczniów według nazw ulic i dopiero później zliczyć poszczególne grupy.
Linia 1. SELECT ulica przecinek COUNT otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły liczba podkreślnik uczniow.
Linia 2. FROM uczniowie.
Linia 3. GROUP BY ulica.
Linia 4. ORDER BY liczba podkreślnik uczniow ASC średnik.
SELECT ulica, COUNT(id_ucz) liczba_uczniow
FROM uczniowie
GROUP BY ulica
ORDER BY liczba_uczniow ASC;
Na przykładzie tego zapytania widzimy, że do grupowania rekordów służy klauzula GROUP BY, po której podajemy nazwę pola. Ponadto w klauzuli SELECT uwzględniliśmy pole ulica, aby widzieć nazwy ulic, dla których zliczamy uczniów. Zapytanie pokazuje również, że klauzula AS jest opcjonalna, kiedy tworzymy aliasy pól. Klauzulę sortowania ORDER BY dodaliśmy dla czytelności wyników.
Początkowe zwrócone rekordy:
Linia 1. Kosmiczna 6.
Linia 2. Worcella 6.
Linia 3. Ksiezycowa 7.
Linia 4. Baczynskiego 8.
Linia 5. Kopernika 8.
Grupowanie poprzedza operacje wykonywane przez funkcje agregujące (np. COUNT()), które mogą działać na wszystkich rekordach, na jednej grupie lub na wielu grupach.
Polecenie 2
Napiszmy kwerendę, która poda liczbę uczniów w poszczególnych klasach.
Uzyskanie takiej informacji wymaga sięgnięcia tylko do jednej tabeli, czyli uczniowie. W klauzuli SELECT wybieramy pole klasa, według którego grupujemy rekordy, oraz pole id_ucz, które zliczamy. W ten sposób otrzymamy tabelę z liczbą uczniów w poszczególnych klasach.
Linia 1. SELECT klasa przecinek COUNT otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły liczba podkreślnik uczniow.
Linia 2. FROM uczniowie.
Linia 3. GROUP BY klasa średnik.
SELECT klasa, COUNT(id_ucz) liczba_uczniow
FROM uczniowie
GROUP BY klasa;
Początkowe zwrócone rekordy:
Linia 1. 1a 30.
Linia 2. 1b 29.
Linia 3. 1c 30.
Linia 4. 1d 27.
Linia 5. 1e 32.
1a 30
1b 29
1c 30
1d 27
1e 32
Polecenie 3
Napiszmy kwerendę, która wyświetli średnią ocen poszczególnych klas.
Problem sugeruje, że należy pogrupować uczniów według klas, a następnie policzyć średnią ich ocen. Źródłem kwerendy będzie zatem tabela uczniowie. Z niej wybieramy pole klasa, według którego będą grupowane rekordy. Drugą wymaganą tabelą będą oceny, z której dodajemy pole ocena i nakładamy na nie funkcję AVG() wyliczającą średnią. Zapis w języku SQL:
Linia 1. SELECT klasa przecinek AVG otwórz nawias okrągły ocena zamknij nawias okrągły srednia podkreślnik ocen.
Linia 2. FROM oceny przecinek uczniowie.
Linia 3. USING otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły.
Linia 4. GROUP BY klasa średnik.
SELECT klasa, AVG(ocena) srednia_ocen
FROM oceny, uczniowie
USING (id_ucz)
GROUP BY klasa;
Do złączenia tabel użyliśmy klauzuli USING, która może zastąpić klauzulę JOIN ON, jeżeli pola tworzące relację mają taką samą nazwę. Wyświetlone średnie ocen można zaokrąglić przy użyciu funkcji ROUND(), której argumentami są średnia ocena wyliczona przez funkcję AVG() oraz precyzja. Początek kwerendy będzie miał wtedy postać:
Linia 1. 1a 2 kropka 96.
Linia 2. 1b 3.
Linia 3. 1c 3 kropka 03.
Linia 4. 1d 2 kropka 99.
Linia 5. 1e 2 kropka 96.
1a 2.96
1b 3
1c 3.03
1d 2.99
1e 2.96
Polecenie 4
Napiszmy zapytanie, które zwróci nazwę przedmiotu z najniższą średnią ocen.
Źródłem danych w zapytaniu będą tabele oceny i przedmioty. Dane trzeba pogrupować według pola nazwa z tabeli przedmioty. W klauzuli SELECT obok nazwy przedmiotu umieścimy funkcję AVG(), której przekażemy jako argument pole ocena. Rekordy uporządkujemy rosnąco według średnich ocen, a ich liczbę ograniczymy do jednego.
Kod SQL prezentuje się następująco:
Linia 1. SELECT przedmioty kropka nazwa Przedmiot przecinek AVG otwórz nawias okrągły ocena zamknij nawias okrągły Średnia.
Linia 2. FROM oceny przecinek przedmioty.
Linia 3. WHERE oceny kropka id podkreślnik prz znak równości przedmioty kropka id podkreślnik prz.
Linia 4. GROUP BY przedmioty kropka nazwa.
Linia 5. ORDER BY Średnia ASC.
Linia 6. LIMIT 1.
SELECT przedmioty.nazwa Przedmiot, AVG(ocena) Średnia
FROM oceny, przedmioty
WHERE oceny.id_prz = przedmioty.id_prz
GROUP BY przedmioty.nazwa
ORDER BY Średnia ASC
LIMIT 1
Operacja grupowania nie wyklucza sortowania w klauzuli ORDER BY ani ograniczania liczby zwracanych rekordów w klauzuli LIMIT.
Wynik kwerendy:
Linia 1. informatyka 2 kropka 93494228751312.
informatyka 2.93494228751312
Ważne!
Sortowanie następuje po grupowaniu. Tym samym w klauzuli sortowania można podać pola, według których następuje grupowanie, lub pola, na których wykonywana jest funkcja agregująca.
Użycie podzapytań
Polecenie 5
Napiszmy zapytanie, które zwróci średnie ocen z poszczególnych przedmiotów podanej klasy, np. 1a.
Rozwiązanie zaczniemy od skonstruowania zapytania, które pobierze wszystkie oceny uczniów z podanej klasy. W wynikach kwerendy chcemy mieć nazwę klasy, nazwę przedmiotu oraz oceny, dlatego w klauzuli SELECT umieszczamy pola klasa, nazwa i ocena. Każde z tych pól jest w innej tabeli, warunki złączenia definiujemy za pomocą pól id_prz oraz id_ucz, które tworzą relację, w klauzuli WHERE. Dodajemy również warunek pozwalający wybrać rekordy klasy 1a. Kod SQL:
Linia 1. SELECT klasa przecinek nazwa przecinek ocena.
Linia 2. FROM oceny przecinek przedmioty przecinek uczniowie.
Linia 3. WHERE oceny kropka id podkreślnik prz znak równości przedmioty kropka id podkreślnik prz.
Linia 4. AND oceny kropka id podkreślnik ucz znak równości uczniowie kropka id podkreślnik ucz.
Linia 5. AND klasa znak równości apostrof 1a apostrof średnik.
SELECT klasa, nazwa, ocena
FROM oceny, przedmioty, uczniowie
WHERE oceny.id_prz = przedmioty.id_prz
AND oceny.id_ucz = uczniowie.id_ucz
AND klasa = '1a';
Wynikiem kwerendy będzie tabela ocen podanej klasy. Początkowe rekordy:
Linia 1. 1a niemiecki 4.
Linia 2. 1a angielski 3.
Linia 3. 1a niemiecki 3.
Linia 4. 1a niemiecki 4.
Linia 5. 1a fizyka 4.
1a niemiecki 4
1a angielski 3
1a niemiecki 3
1a niemiecki 4
1a fizyka 4
Teraz zaprojektujemy końcową kwerendę, która pogrupuje oceny według nazw przedmiotów, obliczy średnią dla każdej grupy i wyświetli nazwy przedmiotów oraz średnie ocen. Poprzednie zapytanie umieścimy w klauzuli FROM jako źródło końcowej kwerendy.
Kod SQL przyjmie postać:
Linia 1. SELECT nazwa przecinek AVG otwórz nawias okrągły ocena zamknij nawias okrągły.
Linia 2. FROM.
Linia 3. otwórz nawias okrągły SELECT klasa przecinek nazwa przecinek ocena.
Linia 4. FROM oceny przecinek przedmioty przecinek uczniowie.
Linia 5. WHERE oceny kropka id podkreślnik prz znak równości przedmioty kropka id podkreślnik prz.
Linia 6. AND oceny kropka id podkreślnik ucz znak równości uczniowie kropka id podkreślnik ucz.
Linia 7. AND klasa znak równości apostrof 1a apostrof zamknij nawias okrągły.
Linia 8. GROUP BY nazwa średnik.
SELECT nazwa, AVG(ocena)
FROM
(SELECT klasa, nazwa, ocena
FROM oceny, przedmioty, uczniowie
WHERE oceny.id_prz = przedmioty.id_prz
AND oceny.id_ucz = uczniowie.id_ucz
AND klasa = '1a')
GROUP BY nazwa;
Ważne!
Kwerendy wykorzystywane wewnątrz innej kwerendy nazywamy podzapytaniami. Po podzapytaniach nie stawiamy średników, są one wykonywane w pierwszej kolejności.
Ćwiczenie 2
Dodaj do ostatniej kwerendy sortowanie malejące wyników według średniej ocen z przedmiotów.
Na końcu kwerendy należy dopisać klauzulę ORDER BY i podać wartość 2, aby wskazać drugie pole wybierane w zapytaniu, czyli średnią ocen:
Linia 1. ORDER BY 2 DESC.
ORDER BY 2 DESC
Można użyć funkcji agregującej:
Linia 1. ORDER BY AVG otwórz nawias okrągły ocena zamknij nawias okrągły DESC.
ORDER BY AVG(ocena) DESC
Można również stworzyć alias AVG(ocena) srednia i użyć go do sortowania:
Linia 1. ORDER BY srednia DESC.
ORDER BY srednia DESC
Kwerenda parametryczna
Ostatnia kwerenda byłaby o wiele bardziej użyteczna, gdyby pozwalała na podawanie nazwy klasy przed wykonaniem. Taką możliwość łatwo uzyskać, przekształcając zapytanie w kwerendę parametrycznąkwerenda parametrycznakwerendę parametryczną. Wystarczy zamiast nazwy klasy wpisać znak zapytania. Zapytanie przyjmie następującą postać:
Linia 1. SELECT nazwa przecinek AVG otwórz nawias okrągły ocena zamknij nawias okrągły.
Linia 2. FROM.
Linia 3. otwórz nawias okrągły SELECT klasa przecinek nazwa przecinek ocena.
Linia 4. FROM oceny przecinek przedmioty przecinek uczniowie.
Linia 5. WHERE oceny kropka id podkreślnik prz znak równości przedmioty kropka id podkreślnik prz.
Linia 6. AND oceny kropka id podkreślnik ucz znak równości uczniowie kropka id podkreślnik ucz.
Linia 7. AND klasa znak równości znak zapytania zamknij nawias okrągły.
Linia 8. GROUP BY nazwa średnik.
SELECT nazwa, AVG(ocena)
FROM
(SELECT klasa, nazwa, ocena
FROM oceny, przedmioty, uczniowie
WHERE oceny.id_prz = przedmioty.id_prz
AND oceny.id_ucz = uczniowie.id_ucz
AND klasa = ?)
GROUP BY nazwa;
RzIH6SAyF2Ubk
Okno Parametry zapytania w programie SQLiteStudio. Tytuł okna Parametry zapytania. Proszę podać wartości dla parametrów zapytania. [1]? opcja do wyboru Wartość null. Poniżej dwie zakładki: Liczba oraz Tekst. Wyświetlono Tekst. W polu wpisani 1a. Poniżej dwa przyciski Abort, OK.
Okno Parametry zapytania w programie SQLiteStudio.
Źródło: Contentplus.pl sp. z o.o., licencja: CC BY-ND 3.0.
Podane zapytanie wykona się w programie SQLiteStudio, który wyświetli okno dialogowe pozwalające podać odpowiednią wartość. Nazwę klasy należy wprowadzić w zakładce Tekst i kliknąć OK.
W wierszu poleceń bazy SQLite lub w zapytaniach wykonywanych przy użyciu skryptu Pythona kwerenda nie zadziała.
Filtrowanie grup rekordów
Polecenie 6
Napiszmy zapytanie, które zwróci nazwy i średnią ocen klas, jeżeli średnia ocen będzie większa od 3.
Problem postawiony w zadaniu podobny jest do zadania, w którym chcieliśmy otrzymać średnie oceny wszystkich klas. Rozwiązanie opiera się więc na poprzedniej kwerendzie:
Linia 1. SELECT klasa przecinek AVG otwórz nawias okrągły ocena zamknij nawias okrągły srednia podkreślnik ocen.
Linia 2. FROM oceny przecinek uczniowie.
Linia 3. USING otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły.
Linia 4. GROUP BY klasa.
Linia 5. HAVING srednia podkreślnik ocen zamknij nawias ostrokątny 3 średnik.
SELECT klasa, AVG(ocena) srednia_ocen
FROM oceny, uczniowie
USING(id_ucz)
GROUP BY klasa
HAVING srednia_ocen > 3;
Nowością jest klauzula HAVING, która może występować tylko po klauzuli grupującej. Używamy jej wtedy, kiedy nakładamy jakieś warunki na grupy rekordów.
Zwrócone rekordy:
Linia 1. 1c 3 kropka 03068783068783.
Linia 2. 2a 3 kropka 02972195589645.
Linia 3. 2d 3 kropka 04003724394786.
Linia 4. 3b 3 kropka 01615074024226.
Linia 5. 3e 3 kropka 02485795454545.
1c 3.03068783068783
2a 3.02972195589645
2d 3.04003724394786
3b 3.01615074024226
3e 3.02485795454545
Warunki z klauzuli WHERE nakładane są przed grupowaniem. Tym samym odfiltrowane rekordy nie są brane pod uwagę przy grupowaniu. W powyższym przykładzie moglibyśmy wykluczyć z otrzymanego zestawienia, np. klasy o profilu matematycznym. Na potrzeby przykładu załóżmy, że są to wszystkie klasy z literą „a” w nazwie:
Linia 1. SELECT klasa przecinek AVG otwórz nawias okrągły ocena zamknij nawias okrągły srednia podkreślnik ocen.
Linia 2. FROM oceny przecinek uczniowie.
Linia 3. USING otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły.
Linia 4. WHERE klasa NOT LIKE apostrof procent a apostrof.
Linia 5. GROUP BY klasa.
Linia 6. HAVING srednia podkreślnik ocen zamknij nawias ostrokątny 3 średnik.
SELECT klasa, AVG(ocena) srednia_ocen
FROM oceny, uczniowie
USING(id_ucz)
WHERE klasa NOT LIKE '%a'
GROUP BY klasa
HAVING srednia_ocen > 3;
Zwrócone rekordy:
Linia 1. 1c 3 kropka 03068783068783.
Linia 2. 2d 3 kropka 04003724394786.
Linia 3. 3b 3 kropka 01615074024226.
Linia 4. 3e 3 kropka 02485795454545.
1c 3.03068783068783
2d 3.04003724394786
3b 3.01615074024226
3e 3.02485795454545
Słownik
grupowanie
grupowanie
tworzenie zbiorów rekordów na podstawie takich samych wartości z podanej kolumny; grupowanie zazwyczaj poprzedza zastosowanie funkcji agregującej, która przeprowadza obliczenia na grupie rekordów
kwerenda parametryczna
kwerenda parametryczna
kwerenda, w której wartości w wyrażeniach warunkowych są parametrem podawanym przed wykonaniem zapytania; parametry oznaczane są znakami zapytania