SQL od podstaw — w stronę INF.03
Każdy temat ma tę samą budowę: krótkie wyjaśnienie, potem przykład z gotowym rozwiązaniem (rozwiń, żeby zobaczyć zapytanie), a obok analogiczne zadanie — bez rozwiązania, do napisania samodzielnie tą samą metodą. Wszystkie zapytania działają na tej samej, prostej bazie danych, więc od razu widać, jak kolejne polecenia się na siebie nakładają.
Jak wykonujemy zapytania SQL?
Zapytanie SQL można wykonać na dwa sposoby: wpisując je bezpośrednio w narzędziu do zarządzania bazą, np. phpMyAdmin (szybkie testy), albo umieszczając je w kodzie PHP, który łączy się z bazą i przetwarza wynik (tak wygląda to na egzaminie INF.03, gdzie strona wyświetla dane z bazy).
W panelu phpMyAdmin wybierasz bazę biblioteka, wchodzisz w zakładkę SQL i wpisujesz zapytanie. Wynik pojawia się od razu w tabeli poniżej.
SELECT * FROM ksiazki;
To dobry sposób na testowanie zapytań, zanim wstawisz je do kodu PHP.
Tak łączymy się z bazą i wykonujemy zapytanie w kodzie PHP — to standardowy szkielet na egzaminie:
<?php
$polaczenie = mysqli_connect("localhost", "root", "", "biblioteka");
$wynik = mysqli_query($polaczenie, "SELECT * FROM ksiazki");
while ($wiersz = mysqli_fetch_assoc($wynik)) {
echo $wiersz["tytul"] . " (" . $wiersz["rok_wydania"] . ")<br>";
}
?>
Zasada: mysqli_connect(host, użytkownik, hasło, baza) łączy się z bazą, mysqli_query() wykonuje zapytanie, a mysqli_fetch_assoc() pobiera po jednym wierszu jako tablicę asocjacyjną.
-- Baza danych używana w sekcjach 1-11: biblioteka
CREATE TABLE ksiazki (
id INT PRIMARY KEY AUTO_INCREMENT,
tytul VARCHAR(150),
autor VARCHAR(100),
rok_wydania INT,
cena DECIMAL(6,2),
dostepna TINYINT(1)
);
CREATE TABLE czytelnicy (
id INT PRIMARY KEY AUTO_INCREMENT,
imie_nazwisko VARCHAR(100),
email VARCHAR(100),
miasto VARCHAR(50)
);
CREATE TABLE wypozyczenia (
id INT PRIMARY KEY AUTO_INCREMENT,
id_ksiazki INT,
id_czytelnika INT,
data_wypozyczenia DATE,
data_zwrotu DATE NULL,
FOREIGN KEY (id_ksiazki) REFERENCES ksiazki(id),
FOREIGN KEY (id_czytelnika) REFERENCES czytelnicy(id)
);
ksiazki, czytelnicy i wypozyczenia (łączy pierwsze dwie). Ta sama baza wraca w sekcjach 1–11 — warto ją sobie utworzyć i wypełnić przykładowymi wierszami zanim zaczniesz.SELECT — wybieranie kolumn
SELECT określa, które kolumny chcemy zobaczyć, a FROM — z jakiej tabeli. Gwiazdka * oznacza „wszystkie kolumny”.
Wybierz tylko tytuł i autora z tabeli ksiazki.
Rozwiązanie
SELECT tytul, autor FROM ksiazki;Wybierz kolumny imie_nazwisko i miasto z tabeli czytelnicy.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Nazwy kolumn w wyniku można zmienić za pomocą AS — to nie zmienia danych, tylko nagłówki w wyniku.
Rozwiązanie
SELECT tytul AS "Nazwa książki", autor AS "Autor"
FROM ksiazki;Wyświetl kolumnę cena jako "Cena" i rok_wydania jako "Rok", z tabeli ksiazki.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
WHERE — filtrowanie wierszy
WHERE ogranicza wynik do wierszy spełniających warunek. Operatory: =, >, <, >=, <=, <> (różne od). Warunki można łączyć za pomocą AND, OR i NOT.
Wybierz wszystkie książki wydane po roku 2010.
Rozwiązanie
SELECT * FROM ksiazki
WHERE rok_wydania > 2010;Wybierz wszystkie książki, których cena jest niższa niż 30 zł.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Wybierz książki wydane po roku 2000, które są aktualnie dostępne.
Rozwiązanie
SELECT * FROM ksiazki
WHERE rok_wydania > 2000 AND dostepna = 1;Wybierz książki, które zostały wydane przed rokiem 2000 albo kosztują więcej niż 100 zł.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
ORDER BY i LIMIT
ORDER BY sortuje wynik: ASC rosnąco (domyślnie), DESC malejąco. LIMIT ogranicza liczbę zwróconych wierszy.
Wyświetl tytuł i rok wydania, sortując od najnowszej książki.
Rozwiązanie
SELECT tytul, rok_wydania FROM ksiazki
ORDER BY rok_wydania DESC;Wyświetl tytuł i cenę wszystkich książek, sortując od najtańszej do najdroższej.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Wyświetl 3 najdroższe książki.
Rozwiązanie
SELECT tytul, cena FROM ksiazki
ORDER BY cena DESC
LIMIT 3;Wyświetl 5 najstarszych książek w bibliotece (najniższy rok wydania).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Wzorce z LIKE, IN i BETWEEN
LIKE szuka tekstu według wzorca: % zastępuje dowolny ciąg znaków, _ jeden znak. IN sprawdza przynależność do listy wartości, a BETWEEN — czy wartość leży w zakresie.
Znajdź wszystkie książki, których autor zaczyna się od „Sienkiewicz”.
Rozwiązanie
SELECT * FROM ksiazki
WHERE autor LIKE 'Sienkiewicz%';Znajdź wszystkie książki, których tytuł zawiera gdziekolwiek słowo „Pan” (np. „Pan Tadeusz”).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Wybierz książki wydane między rokiem 1990 a 2000 (włącznie).
Rozwiązanie
SELECT * FROM ksiazki
WHERE rok_wydania BETWEEN 1990 AND 2000;Wybierz czytelników, którzy mieszkają w Warszawie, Krakowie albo Gdańsku (użyj IN).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Funkcje agregujące
Funkcje agregujące liczą jedną wartość na podstawie wielu wierszy: COUNT() liczba wierszy, SUM() suma, AVG() średnia, MIN()/MAX() wartość najmniejsza/największa.
Policz, ile książek jest w bazie.
Rozwiązanie
SELECT COUNT(*) AS liczba_ksiazek
FROM ksiazki;Policz, ile czytelników mieszka w Warszawie (połącz COUNT() z WHERE).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Policz średnią cenę książki w bibliotece.
Rozwiązanie
SELECT AVG(cena) AS srednia_cena
FROM ksiazki;Znajdź najstarszy i najnowszy rok wydania książki w jednym zapytaniu (użyj MIN() i MAX()).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
GROUP BY i HAVING
GROUP BY dzieli wiersze na grupy według wartości kolumny i liczy funkcję agregującą dla każdej grupy osobno. HAVING filtruje grupy — działa jak WHERE, ale po zgrupowaniu.
Policz, ile książek ma w bazie każdy autor.
Rozwiązanie
SELECT autor, COUNT(*) AS liczba_ksiazek
FROM ksiazki
GROUP BY autor;Policz, ile czytelników jest zarejestrowanych w każdym mieście.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Wyświetl tylko tych autorów, którzy mają więcej niż 1 książkę w bazie.
Rozwiązanie
SELECT autor, COUNT(*) AS liczba_ksiazek
FROM ksiazki
GROUP BY autor
HAVING liczba_ksiazek > 1;Wyświetl tylko te miasta, w których jest więcej niż 2 czytelników.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
JOIN — łączenie dwóch tabel
Tabela wypozyczenia sama w sobie nie mówi wiele — przechowuje same identyfikatory. JOIN ... ON (czyli INNER JOIN) łączy ją z tabelami ksiazki i czytelnicy, żeby wyświetlić czytelne dane.
Wyświetl tytuł wypożyczonej książki wraz z datą wypożyczenia.
Rozwiązanie
SELECT k.tytul, w.data_wypozyczenia
FROM wypozyczenia w
JOIN ksiazki k ON w.id_ksiazki = k.id;Wyświetl imię i nazwisko czytelnika wraz z datą zwrotu, łącząc wypozyczenia z czytelnicy.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
LEFT JOIN i łączenie wielu tabel
INNER JOIN gubi wiersze, które nie mają dopasowania w drugiej tabeli. LEFT JOIN zachowuje wszystkie wiersze z tabeli po lewej stronie, a tam gdzie nie ma dopasowania — wstawia NULL. Można też łączyć więcej niż dwie tabele naraz.
Znajdź książki, które nigdy nie zostały wypożyczone (nie mają żadnego dopasowania w wypozyczenia).
Rozwiązanie
SELECT k.tytul
FROM ksiazki k
LEFT JOIN wypozyczenia w ON k.id = w.id_ksiazki
WHERE w.id IS NULL;Znajdź czytelników, którzy jeszcze nigdy nic nie wypożyczyli.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Wyświetl tytuł książki, imię i nazwisko czytelnika oraz datę wypożyczenia — trzy tabele naraz.
Rozwiązanie
SELECT k.tytul, c.imie_nazwisko, w.data_wypozyczenia
FROM wypozyczenia w
JOIN ksiazki k ON w.id_ksiazki = k.id
JOIN czytelnicy c ON w.id_czytelnika = c.id;Wyświetl tytuł książki, imię i nazwisko czytelnika oraz datę zwrotu — tylko dla wypożyczeń, które już zostały zwrócone.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
INSERT, UPDATE, DELETE
INSERT dodaje nowy wiersz, UPDATE zmienia istniejące wiersze, DELETE je usuwa. UPDATE i DELETE bez WHERE działają na całej tabeli — zawsze sprawdź warunek przed uruchomieniem.
Zarejestruj nowego czytelnika.
Rozwiązanie
INSERT INTO czytelnicy (imie_nazwisko, email, miasto)
VALUES ('Anna Kowalska', 'anna@example.com', 'Poznań');Dodaj nową książkę do tabeli ksiazki: dowolny tytuł, autor, rok wydania, cena i dostepna = 1.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Oznacz książkę o id = 3 jako niedostępną.
Rozwiązanie
UPDATE ksiazki
SET dostepna = 0
WHERE id = 3;Usuń z tabeli czytelnicy czytelnika o id = 10 (użyj DELETE z WHERE — bez warunku usuniesz wszystkich!).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
CREATE TABLE — typy danych i klucze
Najczęstsze typy danych: INT (liczba całkowita), VARCHAR(n) (tekst do n znaków), DECIMAL(p,s) (liczba z częścią dziesiętną), DATE (data). PRIMARY KEY jednoznacznie identyfikuje wiersz, FOREIGN KEY łączy tabelę z inną poprzez klucz główny.
Stwórz tabelę gatunki z automatycznie numerowanym identyfikatorem i nazwą.
Rozwiązanie
CREATE TABLE gatunki (
id INT PRIMARY KEY AUTO_INCREMENT,
nazwa VARCHAR(50)
);Stwórz tabelę wydawnictwa z kolumnami: id (klucz główny, autonumeracja), nazwa i kraj.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Klucz obcy wymusza, że id_ksiazki musi odpowiadać istniejącemu id z tabeli ksiazki (tak zbudowana jest tabela z sekcji 00).
Rozwiązanie
CREATE TABLE wypozyczenia (
id INT PRIMARY KEY AUTO_INCREMENT,
id_ksiazki INT,
id_czytelnika INT,
data_wypozyczenia DATE,
FOREIGN KEY (id_ksiazki) REFERENCES ksiazki(id),
FOREIGN KEY (id_czytelnika) REFERENCES czytelnicy(id)
);Dodaj do istniejącej tabeli ksiazki nową kolumnę id_gatunku jako klucz obcy do tabeli gatunki (podpowiedź: ALTER TABLE ... ADD COLUMN ..., potem ALTER TABLE ... ADD FOREIGN KEY ...).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Mini-projekt: raport biblioteczny
Zadanie łączy wszystko z sekcji 1–10 na bazie biblioteka. Jak zawsze w mini-projekcie — brak gotowego rozwiązania, tylko kroki do samodzielnej realizacji.
Cel: zestaw zapytań, które razem tworzą prosty raport dla bibliotekarza.
Krok 1. Wstaw do tabel ksiazki, czytelnicy i wypozyczenia po kilka (5–8) przykładowych wierszy, tak żeby część książek była już zwrócona (data_zwrotu wypełniona), a część jeszcze nie (data_zwrotu równe NULL).
Krok 2 — zaległości. Napisz zapytanie, które znajdzie wszystkie wypożyczenia bez zwrotu (data_zwrotu IS NULL), wraz z tytułem książki i danymi czytelnika.
Krok 3 — najpopularniejsze książki. Napisz zapytanie z JOIN i GROUP BY, które policzy, ile razy każda książka została wypożyczona, sortując od najczęściej wypożyczanej.
Krok 4 — aktywność czytelników. Napisz zapytanie, które dla każdego czytelnika policzy liczbę wypożyczeń (użyj LEFT JOIN, żeby nie zgubić czytelników z zerem wypożyczeń).
Krok 5 — wartość zbioru. Policz łączną wartość (SUM(cena)) wszystkich książek aktualnie wypożyczonych (bez zwrotu).
Krok 6 (dodatkowo). Dodaj kolumnę liczba_dni obliczaną jako różnica dni między data_wypozyczenia a dniem dzisiejszym (DATEDIFF(CURDATE(), data_wypozyczenia)) i wybierz tylko wypożyczenia trwające dłużej niż 30 dni bez zwrotu.
Zapytania typowe dla egzaminu INF.03
Poniższe pięć sekcji ćwiczy zapytania w formie, w jakiej najczęściej pojawiają się w arkuszu egzaminacyjnym — z rozbudowanymi warunkami, obliczeniami w SELECT, raportami z kilku tabel naraz i podzapytaniami. Zmieniamy tu bazę danych na sklep — schemat typowy dla zadań o zamówieniach i klientach.
Warunki złożone i wzorce
Egzaminacyjne zadania rzadko mają jeden prosty warunek — zwykle trzeba połączyć kilka z odpowiednim nawiasowaniem, albo dopasować tekst wzorcem.
-- Baza danych używana w sekcjach 12-16: sklep
CREATE TABLE produkty (
id INT PRIMARY KEY AUTO_INCREMENT,
nazwa VARCHAR(100),
cena DECIMAL(8,2),
kategoria VARCHAR(50),
ilosc_magazyn INT
);
CREATE TABLE klienci (
id INT PRIMARY KEY AUTO_INCREMENT,
imie_nazwisko VARCHAR(100),
email VARCHAR(100),
miasto VARCHAR(50)
);
CREATE TABLE zamowienia (
id INT PRIMARY KEY AUTO_INCREMENT,
id_klienta INT,
data_zamowienia DATE,
status VARCHAR(20),
FOREIGN KEY (id_klienta) REFERENCES klienci(id)
);
CREATE TABLE zamowienia_produkty (
id_zamowienia INT,
id_produktu INT,
ilosc INT,
FOREIGN KEY (id_zamowienia) REFERENCES zamowienia(id),
FOREIGN KEY (id_produktu) REFERENCES produkty(id)
);
produkty, klienci, zamowienia i zamowienia_produkty (tabela łącząca zamówienia z produktami, bo jedno zamówienie może zawierać wiele produktów). Ta baza obowiązuje w sekcjach 12–16.Znajdź produkty z kategorii „Elektronika” lub „AGD”, które kosztują między 100 a 500 zł. Zwróć uwagę na nawiasy — bez nich AND/OR działałyby inaczej niż zamierzone.
Rozwiązanie
SELECT * FROM produkty
WHERE (kategoria = 'Elektronika' OR kategoria = 'AGD')
AND cena BETWEEN 100 AND 500;Znajdź produkty, których cena jest niższa niż 50 zł lub których nie ma na magazynie (ilosc_magazyn = 0).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Znajdź produkty, których nazwa zawiera gdziekolwiek słowo „pro” (niezależnie od wielkości liter — LIKE w MySQL domyślnie nie rozróżnia wielkości liter).
Rozwiązanie
SELECT nazwa FROM produkty
WHERE nazwa LIKE '%pro%';Znajdź klientów, których adres e-mail kończy się na @gmail.com.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Obliczenia i aliasy w SELECT
W SELECT można umieścić wyrażenie arytmetyczne albo wywołanie funkcji tekstowej/numerycznej — SQL policzy je dla każdego wiersza. Przydatne funkcje: ROUND() (zaokrąglanie), CONCAT() (łączenie tekstów).
Wyświetl nazwę, cenę i cenę z 23% VAT dla każdego produktu.
Rozwiązanie
SELECT nazwa, cena, cena * 1.23 AS cena_z_vat
FROM produkty;Wyświetl nazwę i cenę produktu po 10% rabacie, jako kolumnę cena_po_rabacie.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Zbuduj jedną kolumnę tekstową z imienia, nazwiska i miasta klienta.
Rozwiązanie
SELECT CONCAT(imie_nazwisko, ' (', miasto, ')') AS opis
FROM klienci;Wyświetl nazwę produktu oraz jego cenę zaokrągloną do pełnych złotych, jako kolumnę cena_zaokraglona (użyj ROUND()).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Złączenia z agregacją — raporty
Najbardziej „egzaminacyjny” typ zapytania: JOIN kilku tabel razem z GROUP BY, żeby policzyć konkretny raport, np. liczbę zamówień na klienta albo sprzedaż na produkt.
Dla każdego klienta policz, ile zamówień złożył.
Rozwiązanie
SELECT k.imie_nazwisko, COUNT(z.id) AS liczba_zamowien
FROM klienci k
JOIN zamowienia z ON k.id = z.id_klienta
GROUP BY k.imie_nazwisko;Dla każdego produktu policz łączną sprzedaną ilość (SUM(ilosc) z tabeli zamowienia_produkty, połączonej z produkty).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Wyświetl tylko tych klientów, którzy złożyli więcej niż 2 zamówienia.
Rozwiązanie
SELECT k.imie_nazwisko, COUNT(z.id) AS liczba_zamowien
FROM klienci k
JOIN zamowienia z ON k.id = z.id_klienta
GROUP BY k.imie_nazwisko
HAVING liczba_zamowien > 2;Wyświetl produkty, które sprzedały się w łącznej ilości większej niż 10 sztuk.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Podzapytania
Podzapytanie (subquery) to zapytanie umieszczone w środku innego zapytania — najczęściej wewnątrz WHERE jako wartość do porównania, albo wewnątrz FROM jako „tabela wynikowa”.
Znajdź produkty droższe niż średnia cena wszystkich produktów.
Rozwiązanie
SELECT nazwa, cena FROM produkty
WHERE cena > (SELECT AVG(cena) FROM produkty);Znajdź klientów, którzy nigdy nie złożyli żadnego zamówienia (podpowiedź: WHERE id NOT IN (SELECT id_klienta FROM zamowienia)).
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Podzapytanie może też służyć jako „tabela” w FROM — tu najpierw liczymy średnią cenę w każdej kategorii, a potem filtrujemy wynik tego zapytania.
Rozwiązanie
SELECT * FROM (
SELECT kategoria, AVG(cena) AS srednia
FROM produkty
GROUP BY kategoria
) AS raport
WHERE srednia > 100;Zbuduj podzapytanie, które liczy łączną wartość zamówień (SUM(ilosc * cena)) na klienta, a następnie w zewnętrznym zapytaniu wybierz tylko klientów, których suma przekracza 500 zł.
-- napisz zapytanie samodzielnie, korzystając z przykładu obok
Projekt egzaminacyjny: baza sklepu internetowego
Zadanie łączy wszystko z bloku egzaminacyjnego na bazie sklep: warunki złożone, obliczenia, złączenia z agregacją i podzapytania. Jak w mini-projekcie z sekcji 11 — brak gotowego rozwiązania, tylko kroki do samodzielnej realizacji.
Cel: pełny zestaw zapytań raportujących dla sklepu internetowego, na bazie ze schematu z sekcji 12.
Krok 1 — dane testowe. Wstaw do tabel produkty, klienci, zamowienia i zamowienia_produkty po kilka wierszy tak, żeby niektóre zamówienia zawierały więcej niż jeden produkt.
Krok 2 — wartość zamówienia. Napisz zapytanie, które dla każdego zamówienia policzy jego łączną wartość: SUM(ilosc * cena) po złączeniu zamowienia_produkty z produkty, zgrupowane po id_zamowienia.
Krok 3 — rabat. Rozbuduj zapytanie z kroku 2 tak, żeby zamówienia o wartości powyżej 1000 zł miały wyliczoną też kolumnę z ceną po 10% rabacie (podpowiedź: wyrażenie CASE WHEN suma > 1000 THEN suma * 0.9 ELSE suma END).
Krok 4 — najlepsi klienci. Napisz zapytanie łączące klienci, zamowienia i zamowienia_produkty, które dla każdego klienta policzy łączną wartość wszystkich jego zamówień, sortując od największej.
Krok 5 — magazyn. Napisz zapytanie znajdujące produkty, których ilosc_magazyn jest niższa niż suma ilości zamówionych tego produktu (czyli zamówienia, które faktycznie wyczyściłyby magazyn) — użyj podzapytania lub złączenia z GROUP BY.
Krok 6 (dodatkowo). Napisz zapytanie z LEFT JOIN, które znajdzie produkty, które nigdy nie zostały zamówione — przydatne do wyczyszczenia oferty ze sklepu.
Gotowa baza danych — teraz ją rozbuduj
Wszystko powyżej to pojedyncze, wyizolowane zapytania. W praktyce na egzaminie dostajesz jednak jedną, gotową bazę danych i musisz do niej dopisać konkretne zapytania albo poprawić istniejące. Dlatego obok tego zbioru ćwiczeń istnieje osobny, gotowy „arkusz uniwersalny”: plik szkola.sql, który tworzy cztery połączone tabele i wypełnia je przykładowymi danymi — gotowy do zaimportowania w phpMyAdmin.
Baza ma trzy niezależne części, każda odpowiadająca innemu typowemu zadaniu z egzaminu: uczniowie i klasy (podstawowe złączenie jeden-do-wielu), przedmioty i oceny (złączenie z tabelą pośredniczącą i agregacja) oraz raporty i statystyki (podzapytania i obliczenia na wynikach agregacji). Plik szkola.sql jest gęsto skomentowany — każda część tłumaczy krok po kroku, do czego służy dana tabela.
szkola.sql
Propozycje rozbudowy bazy szkolnej
Tu nie ma przykładów z gotowym rozwiązaniem — to konkretne zapytania do dopisania bezpośrednio na bazie szkola, obok istniejącego, podobnego kodu. Każda z trzech części ma zadania łatwe (jedna sztuczka), średnie (łączą dwie rzeczy) i trudne (pełny, samodzielny raport) — dokładnie tak, jak stopniowany bywa egzamin praktyczny.
-- szkola.sql (fragment)
CREATE TABLE klasy (
id INT PRIMARY KEY AUTO_INCREMENT,
nazwa VARCHAR(10),
wychowawca VARCHAR(100)
);
CREATE TABLE uczniowie (
id INT PRIMARY KEY AUTO_INCREMENT,
imie_nazwisko VARCHAR(100),
id_klasy INT,
FOREIGN KEY (id_klasy) REFERENCES klasy(id)
);
CREATE TABLE przedmioty (
id INT PRIMARY KEY AUTO_INCREMENT,
nazwa VARCHAR(50)
);
CREATE TABLE oceny (
id INT PRIMARY KEY AUTO_INCREMENT,
id_ucznia INT,
id_przedmiotu INT,
ocena DECIMAL(3,2),
data_wystawienia DATE,
FOREIGN KEY (id_ucznia) REFERENCES uczniowie(id),
FOREIGN KEY (id_przedmiotu) REFERENCES przedmioty(id)
);
klasy → uczniowie → oceny ← przedmioty. Pełny plik szkola.sql zawiera też przykładowe INSERT dla każdej tabeli.Uczniowie i klasy
Łatwe
- Napisz zapytanie wyświetlające wszystkich uczniów wraz z nazwą ich klasy (
JOINzklasy). - Policz, ile uczniów jest w każdej klasie (
GROUP BY).
Średnie
- Wyświetl tylko te klasy, w których jest mniej niż 20 uczniów (
HAVING). - Dodaj nową klasę i przenieś do niej wybranego ucznia za pomocą
UPDATEna kolumnieid_klasy.
Trudne
- Znajdź klasy, które nie mają przypisanego żadnego ucznia — użyj
LEFT JOINzklasyjako tabelą główną i sprawdzeniaIS NULL.
Przedmioty i oceny
Łatwe
- Wyświetl wszystkie oceny konkretnego ucznia (po imieniu i nazwisku) wraz z nazwą przedmiotu.
Średnie
- Policz średnią ocen każdego ucznia ze wszystkich przedmiotów (
AVG+GROUP BY), zaokrągloną do dwóch miejsc (ROUND()). - Wyświetl uczniów, których średnia ocen jest niższa niż 3.5 — wykorzystaj poprzednie zapytanie jako podzapytanie w
FROM.
Trudne
- Policz średnią ocen z każdego przedmiotu w podziale na klasy (złączenie
oceny+uczniowie+klasy+przedmioty,GROUP BYpo klasie i przedmiocie).
Raporty i statystyki
Łatwe
- Znajdź ucznia (lub uczniów) z najwyższą pojedynczą oceną w całej bazie (podpowiedź: podzapytanie z
MAX(ocena)).
Średnie
- Wyświetl przedmiot, z którego wystawiono najwięcej ocen w bieżącym roku (
WHERE YEAR(data_wystawienia) = YEAR(CURDATE()),GROUP BY,ORDER BY,LIMIT 1).
Trudne
- Zbuduj raport rankingowy: dla każdej klasy policz jej średnią ocen ze wszystkich przedmiotów i ucznia z najwyższą średnią w tej klasie — połącz podzapytanie liczące średnią ucznia z zewnętrznym zapytaniem grupującym po klasie.
To już komplet materiału
Siedemnaście sekcji: jedenaście od pierwszego SELECT po mini-projekt na bazie biblioteki, kolejne pięć — wyróżnione czerwienią i osobnym blokiem — to zapytania typowe dla egzaminu praktycznego INF.03 (warunki złożone, obliczenia w SELECT, złączenia z agregacją, podzapytania, projekt egzaminacyjny), a ostatnia, fioletowa sekcja to zadania rozbudowy gotowej bazy szkolnej (szkola.sql), traktowanej jako jeden, spójny projekt. Najlepiej działa to tak: przeczytaj przykład, rozwiń rozwiązanie dopiero gdy utkniesz, a zadanie obok napisz samodzielnie w phpMyAdmin albo w pliku .sql — a zadania z ostatniej sekcji dopisz wprost do bazy szkolnej.