Potwierdzone sprawdzone punkt po punkcie · 2026-11-04
Pomiń nawigację
Materiał edukacyjny · Informatyka Bazy danych · Moduł 05

BAZY DANYCH · INF.03

JOIN — łączenie tabel

Dane o uczniach, książkach i wypożyczeniach leżą w osobnych tabelach. JOIN składa je z powrotem w jeden czytelny obraz: kto co wypożyczył, z której klasy pochodzi i kiedy ma oddać książkę.

INNER JOIN — łączenie tabel po kluczach

Tabela ksiazki nie przechowuje nazwy kategorii ani nazwy wydawnictwa. Zamiast tego ma kolumny kategoria_id i wydawnictwo_id, czyli numery wskazujące wiersze w innych tabelach. Żeby w raporcie pokazać czytelnikowi „Fantastyka” zamiast liczby 2, trzeba połączyć dwie tabele. Do tego służy JOIN.

INNER JOIN zwraca tylko te pary wierszy, które spełniają warunek połączenia. Warunek zapisujemy po słowie ON i najczęściej porównujemy klucz obcy z kluczem podstawowym. Jeśli książka ma kategoria_id = 2, a w tabeli kategorie istnieje wiersz o id = 2, para zostanie dopasowana. Jeśli numer nie istnieje, wiersz nie pojawi się w wyniku.

SELECT k.tytul, kat.nazwa AS kategoria, k.cena
FROM ksiazki k
JOIN kategorie kat ON k.kategoria_id = kat.id
WHERE kat.kod = 'FAN'
ORDER BY k.cena DESC;

Litery k i kat to aliasy tabel. Dzięki nim zapis jest krótszy, a kolumny o tych samych nazwach można jednoznacznie wskazać. W obu tabelach występuje na przykład kolumna id; zapis k.id oznacza identyfikator książki, a kat.id identyfikator kategorii. Bez aliasów baza nie wiedziałaby, o którą kolumnę chodzi.

JOIN można łączyć w łańcuch. Raport wypożyczeń wymaga uczniów, książek i pracowników: każde wypożyczenie wskazuje ucznia, książkę i osobę obsługującą. Każde kolejne JOIN dokłada kolumny do bieżącego wiersza, więc po trzech połączeniach mamy w jednym wierszu dane z czterech tabel. Kolejność łączenia nie zmienia wyniku, ale wpływa na czytelność zapytania.

SELECT u.nazwisko, ks.tytul, w.termin_zwrotu
FROM wypozyczenia w
JOIN uczniowie u ON w.uczen_id = u.id
JOIN ksiazki ks ON w.ksiazka_id = ks.id
WHERE w.status = 'przeterminowane'
ORDER BY w.termin_zwrotu, u.nazwisko;

Relacja wiele-do-wielu wymaga tabeli pośredniej. Książka może mieć kilku autorów, a autor może napisać wiele książek. Tabela ksiazki_autorzy przechowuje pary ksiazka_id i autor_id, a kolumna rola mówi, czy dana osoba jest autorem, czy współautorem. Aby pokazać autorów książki, trzeba połączyć trzy tabele: ksiazki, ksiazki_autorzy i autorzy.

SELECT ks.tytul, a.imie, a.nazwisko, ka.rola
FROM ksiazki ks
JOIN ksiazki_autorzy ka ON ks.id = ka.ksiazka_id
JOIN autorzy a ON ka.autor_id = a.id
WHERE ks.id = 4
ORDER BY ka.rola, a.nazwisko;
INNER JOIN: tylko dopasowane pary ksiazki (alias k) id | tytul | kategoria_id | cena 4 | Wiedźmin | 2 | 54,90 5 | Harry Potter | 2 | 59,90 6 | Rok 1984 | 2 | 42,90 1 | Pan Tadeusz | 1 | 39,90 kategoria_id jest kluczem obcym ON k.kategoria_id = kat.id łączenie po kluczu kategorie (alias kat) id | nazwa | kod 1 | Literatura piękna | LIT 2 | Fantastyka | FAN 6 | Dzieci i młodzież | DZI 8 | Podręczniki | POD id jest kluczem podstawowym wynik: tytuł + nazwa kategorii w jednym wierszu
INNER JOIN dopasowuje wiersze po kluczu obcym i kluczu podstawowym. W wyniku pojawiają się tylko książki, dla których istnieje odpowiednia kategoria.
Tabela Łączymy z Warunek Po co
ksiazki kategorie ksiazki.kategoria_id = kategorie.id nazwa kategorii zamiast numeru
ksiazki wydawnictwa ksiazki.wydawnictwo_id = wydawnictwa.id nazwa i miasto wydawcy
ksiazki ksiazki_autorzy ksiazki.id = ksiazki_autorzy.ksiazka_id autorzy i role
wypozyczenia uczniowie, ksiazki wypozyczenia.uczen_id = uczniowie.id, wypozyczenia.ksiazka_id = ksiazki.id kto co wypożyczył
JOIN bez warunku to nie połączenie, lecz iloczyn. Zapytanie FROM ksiazki JOIN kategorie bez ON połączy każdą książkę z każdą kategorią. Przy 24 książkach i 8 kategoriach da 192 wiersze, z których większość nie ma sensu. Warunek ON jest obowiązkowy, jeśli chcemy pary po kluczu.

Przykłady z życia

1. Katalog biblioteczny. Czytelnik widzi tytuł i nazwę kategorii, choć w tabeli książek zapisany jest tylko numer kategorii. JOIN tłumaczy numer na nazwę w chwili wyświetlania, więc zmiana nazwy kategorii wymaga poprawienia jednego wiersza, a nie wszystkich książek.

2. Plan lekcji. Lekcja łączy nauczyciela, przedmiot, klasę i salę. Żadna z tych informacji nie powinna być wpisywana wielokrotnie w jednym wierszu planu. JOIN zbiera je z tabel słownikowych po identyfikatorach, podobnie jak biblioteka łączy książkę z autorem.

3. Zamówienie w sklepie. Pozycja zamówienia wskazuje produkt i zamówienie. Raport „co zamówił klient” wymaga połączenia tabeli pozycji z produktami i zamówieniami. Bez JOIN widzielibyśmy tylko numery, a nie nazwy produktów.

Geografia: mapa cyfrowa łączy warstwę miejscowości z warstwą gmin po identyfikatorze gminy. Nazwa gminy jest przechowywana raz, a miejscowości wskazują ją kluczem — dokładnie jak książki wskazują kategorię. JOIN pozwala nałożyć na siebie obie warstwy bez kopiowania nazw.

Jak to się łączy…

W module 04 filtrowałeś i grupowałeś jedną tabelę. Tutaj dołączasz do niej dane z innych tabel, a w module 06 użyjesz JOIN wewnątrz podzapytań i widoków. W module 07 zobaczysz, jak JOIN współpracuje z usuwaniem i aktualizacją danych, a w module 09 cały raport złożysz w zadaniu egzaminacyjnym.

Informatyka: w aplikacji internetowej lista zamówień zwykle nie pobiera nazw produktów z jednej wielkiej tabeli. Serwis łączy tabelę zamówień z tabelą produktów po kluczu, tak samo jak SQL robi to w bazie. Dzięki temu zmiana nazwy produktu jest widoczna od razu we wszystkich zamówieniach.

Zadanie transferowe 1 — katalog dla rodziców

Biblioteka publikuje krótki katalog dla rodziców. Dla książek z kategorii Literatura piękna i Fantastyka, dostępnych i tańszych niż 60 zł, pokaż tytuł, nazwę kategorii, nazwę wydawnictwa i cenę. Posortuj wynik rosnąco po nazwie kategorii, a w obrębie kategorii malejąco po cenie. Napisz zapytanie z dwoma połączeniami i wyjaśnij, po jakich kluczach łączysz tabele.

Pokaż przykładowe rozwiązanie i kryteria

Przykład: SELECT k.tytul, kat.nazwa AS kategoria, w.nazwa AS wydawnictwo, k.cena FROM ksiazki k JOIN kategorie kat ON k.kategoria_id = kat.id JOIN wydawnictwa w ON k.wydawnictwo_id = w.id WHERE kat.kod IN ('LIT', 'FAN') AND k.cena < 60 AND k.dostepna = 1 ORDER BY kat.nazwa, k.cena DESC, k.tytul; Pierwsze połączenie tłumaczy numer kategorii na nazwę, drugie numer wydawnictwa na nazwę wydawcy.

Kryteria: (1) połączenia — użyto dwóch JOIN-ów po właściwych kluczach; (2) filtr — uwzględniono kategorię, cenę i dostępność; (3) wynik — wybrano cztery kolumny i poprawnie posortowano; (4) uzasadnienie — uczeń wskazuje klucz obcy i klucz podstawowy w każdym połączeniu.

1. Co zwraca INNER JOIN dwóch tabel?
1. Co zwraca INNER JOIN dwóch tabel?
2. Po co w zapytaniu łączącym ksiazki z kategorie używamy aliasów k i kat?
2. Po co w zapytaniu łączącym ksiazki z kategorie używamy aliasów k i kat?
3. Ile wierszy powstanie, jeśli połączysz 24 książki z 8 kategoriami bez warunku ON?
3. Ile wierszy powstanie, jeśli połączysz 24 książki z 8 kategoriami bez warunku ON?

LEFT JOIN i RIGHT JOIN — wiersze bez pary

INNER JOIN pokazuje tylko dopasowane pary. To dobre pytanie „które książki mają kategorię”, ale złe pytanie „które kategorie nie mają żadnej książki”. Jeśli po prawej stronie nie ma pasującego wiersza, INNER JOIN po cichu go pomija. Wtedy wynik wygląda na kompletny, choć brakuje w nim najważniejszej informacji: braku.

LEFT JOIN zachowuje wszystkie wiersze z tabeli po lewej stronie, nawet jeśli nie mają pary po prawej. Dla niepasującego wiersza kolumny prawej tabeli przyjmują wartość NULL. Dzięki temu można zobaczyć zarówno uczniów, którzy wypożyczyli książkę, jak i tych, którzy nie wypożyczyli nic. Wiersz ucznia bez wypożyczeń ma w kolumnach wypożyczenia same wartości NULL.

SELECT u.imie, u.nazwisko, w.id AS wypozyczenie
FROM uczniowie u
LEFT JOIN wypozyczenia w ON u.id = w.uczen_id
ORDER BY u.nazwisko;

Wynik ma 47 wierszy: 45 wypożyczeń oraz dwóch uczniów bez żadnego wypożyczenia. Każdy z tych dwóch uczniów pojawia się raz, z NULL w kolumnie wypozyczenie. To właśnie ten NULL pozwala odróżnić „nie ma wypożyczenia” od „wypożyczenie ma numer zero”, którego w bazie nie używamy.

Filtr w WHERE a filtr w ON. To najczęstsza pułapka outer joinów. Warunek dopisany do ON decyduje, które wiersze prawej tabeli mogą się dopasować; warunek w WHERE sprawdzamy już po połączeniu i może odrzucić wiersze z NULL. Jeśli chcesz zachować wszystkich aktywnych uczniów i tylko oznaczyć tych z aktywnym wypożyczeniem, status umieść w ON.

SELECT u.imie, u.nazwisko, w.id AS aktywne_wypozyczenie
FROM uczniowie u
LEFT JOIN wypozyczenia w
  ON u.id = w.uczen_id AND w.status = 'w trakcie'
WHERE u.aktywny = 1
ORDER BY u.nazwisko;

Gdyby warunek w.status = 'w trakcie' przenieść do WHERE, uczniowie bez aktywnego wypożyczenia mieliby NULL w kolumnie statusu, a porównanie z NULL odrzuciłoby ich wiersze. LEFT JOIN zamieniłby się w praktyce w INNER JOIN, choć w zapisie nadal widnieje słowo LEFT.

RIGHT JOIN jest lustrzanym odbiciem LEFT JOIN. Zachowuje wszystkie wiersze z tabeli po prawej stronie. Zamiast pisać FROM wypozyczenia w RIGHT JOIN uczniowie u, można zamienić tabele miejscami i napisać FROM uczniowie u LEFT JOIN wypozyczenia w — wynik będzie ten sam, a zapytanie czytelniejsze. W praktyce częściej używa się LEFT JOIN, bo łatwiej czyta się je od tabeli, którą chcemy zachować w całości.

SELECT u.nazwisko, w.id AS wypozyczenie
FROM wypozyczenia w
RIGHT JOIN uczniowie u ON w.uczen_id = u.id
ORDER BY u.nazwisko;
RIGHT JOIN w edytorze kursu. Edytor ćwiczeń obsługuje podstawowy zakres JOIN-ów; pełny wariant RIGHT JOIN sprawdzisz w phpMyAdmin na XAMPP. W edytorze użyj równoważnego zapisu FROM uczniowie u LEFT JOIN wypozyczenia w — daje ten sam wynik i jest czytelniejszy.
Rodzaj połączenia Które wiersze zostają Przykład w bibliotece Liczba wierszy
INNER JOIN tylko pary z obu tabel wypożyczenia z przypisanym uczniem 45
LEFT JOIN wszyscy z lewej plus dopasowania uczniowie i ich wypożyczenia, także brak 47
RIGHT JOIN wszyscy z prawej plus dopasowania to samo co LEFT JOIN po zamianie tabel 47
NULL po LEFT JOIN to nie błąd. W kolumnach prawej tabeli NULL oznacza „nie znaleziono dopasowania”. Jeśli po połączeniu sprawdzasz COUNT(w.id), policzysz tylko dopasowane wypożyczenia. COUNT(*) policzy także wiersze bez dopasowania, czyli wszystkich uczniów. Wybór funkcji zmienia sens raportu.

Przykłady z życia

1. Lista uczestników wycieczki. Wychowawca ma pełną listę uczniów i osobno zapisane zgody. LEFT JOIN pokazuje wszystkich uczniów, a brak zgody jako NULL. Dzięki temu od razu widać, kto jeszcze nie oddał podpisu, zamiast zgubić te osoby w wyniku INNER JOIN.

2. Klienci bez zamówień. Sklep chce wysłać ofertę osobom, które nigdy nic nie kupiły. LEFT JOIN klientów z zamówieniami i warunek zamowienie.id IS NULL daje właśnie taką listę. To klasyczny wzorzec „kto nie ma powiązanego rekordu”.

3. Awarie bez zgłoszenia. Serwis ma listę maszyn i listę zgłoszeń. LEFT JOIN pokazuje także maszyny, które nie mają żadnego zgłoszenia. Brak zgłoszenia może oznaczać, że wszystko działa, albo że nikt nie zauważył problemu — dlatego raport jest potrzebny.

Geografia: lista stacji meteorologicznych połączona z pomiarami przez LEFT JOIN pokaże także stacje, które nie przesłały danych. INNER JOIN ukryłby je, a właśnie brak pomiaru jest często najważniejszą informacją w monitoringu środowiska.

Jak to się łączy…

W poprzedniej sekcji łączyłeś tylko dopasowane wiersze. Tutaj uczysz się widzieć brak dopasowania. W module 04 liczyłeś już agregaty, a w module 06 znajdziesz uczniów bez wypożyczeń także przez NOT IN i NOT EXISTS. W module 07 zobaczysz, co się dzieje z powiązaniami przy usuwaniu danych.

Informatyka: panel administracyjny często pokazuje „użytkownicy bez aktywnej subskrypcji”. To zapytanie z LEFT JOIN i warunkiem IS NULL. Bez outer joinu programista musiałby wykonać dwa osobne zapytania i porównać listy w kodzie, co łatwo prowadzi do błędów.

4. Uczeń nie ma żadnego wypożyczenia. Co pokaże LEFT JOIN uczniów z wypożyczeniami?
4. Uczeń nie ma żadnego wypożyczenia. Co pokaże LEFT JOIN uczniów z wypożyczeniami?
5. Chcesz zachować wszystkich uczniów, a tylko niektórym dopasować aktywne wypożyczenia. Gdzie umieścisz warunek statusu?
5. Chcesz zachować wszystkich uczniów, a tylko niektórym dopasować aktywne wypożyczenia. Gdzie umieścisz warunek statusu?
6. Czemu odpowiada zapis FROM wypozyczenia RIGHT JOIN uczniowie?
6. Czemu odpowiada zapis FROM wypozyczenia RIGHT JOIN uczniowie?

Zapytania wielotabelowe — raport wypożyczeń

Prawdziwy raport rzadko mieści się w jednej tabeli. Biblioteka chce pokazać nazwisko ucznia, jego klasę, tytuł książki, kategorię i kwotę kary. Te informacje są rozłożone na pięć tabel: uczniowie, klasy, ksiazki, kategorie i wypozyczenia. Zapytanie wielotabelowe łączy je w jeden czytelny wiersz.

Zaczynamy od tabeli zdarzeń, czyli wypozyczenia. Każdy jej wiersz wskazuje ucznia, książkę i pracownika. Dołączamy uczniów po w.uczen_id = u.id, klasy po u.klasa_id = kl.id, książki po w.ksiazka_id = ks.id, a kategorie po ks.kategoria_id = kat.id. Każde JOIN dokłada kolumny do bieżącego wyniku, więc po całym łańcuchu mamy w jednym wierszu dane z pięciu tabel.

SELECT u.nazwisko, kl.nazwa AS klasa, ks.tytul,
       kat.nazwa AS kategoria, w.kara
FROM wypozyczenia w
JOIN uczniowie u ON w.uczen_id = u.id
JOIN klasy kl ON u.klasa_id = kl.id
JOIN ksiazki ks ON w.ksiazka_id = ks.id
JOIN kategorie kat ON ks.kategoria_id = kat.id
WHERE w.kara > 0
ORDER BY w.kara DESC, u.nazwisko;

Kolejność łączenia nie jest przypadkowa. Zaczynamy od tabeli, która ma najwięcej wierszy w raporcie, i dołączamy do niej tabele słownikowe. Dzięki temu łatwo zauważyć, którego klucza brakuje. Warto też od razu nadawać aliasy i kwalifikować kolumny: w kilku tabelach występuje id i nazwa, więc zapis bez aliasu byłby niejednoznaczny.

Połączenie tabel a grupowanie to dwa etapy. Najpierw JOIN tworzy pełne wiersze, a dopiero potem GROUP BY zbiera je w grupy. Raport „ile wypożyczeń ma każda klasa” wymaga połączenia klas, uczniów i wypożyczeń, a następnie grupowania po nazwie klasy. COUNT(w.id) policzy wypożyczenia, a SUM(w.kara) sumę kar w danej klasie.

SELECT kl.nazwa AS klasa,
       COUNT(w.id) AS wypozyczenia,
       SUM(w.kara) AS suma_kar
FROM klasy kl
JOIN uczniowie u ON kl.id = u.klasa_id
JOIN wypozyczenia w ON u.id = w.uczen_id
GROUP BY kl.nazwa
ORDER BY wypozyczenia DESC, kl.nazwa;

Raport przekrojowy grupuje po dwóch kolumnach. Zestawienie klas i statusów wypożyczeń pokazuje, ile w każdej klasie jest zwrotów, książek w trakcie i przeterminowań. Każda para klasa–status tworzy osobną grupę, więc wynik ma więcej wierszy niż liczba klas. To nadal jedno zapytanie, choć tabela wygląda jak kilka raportów zestawionych obok siebie.

SELECT kl.nazwa AS klasa, w.status, COUNT(*) AS liczba
FROM klasy kl
JOIN uczniowie u ON kl.id = u.klasa_id
JOIN wypozyczenia w ON u.id = w.uczen_id
GROUP BY kl.nazwa, w.status
ORDER BY kl.nazwa, w.status;
Ścieżka połączeń w raporcie wypożyczeń wypozyczenia id (PK) uczen_id (FK) ksiazka_id (FK) kara, status uczniowie id (PK) imie, nazwisko klasa_id (FK) klasy id (PK) nazwa wychowawca ksiazki id (PK) tytul kategoria_id (FK) kategorie id (PK) nazwa, kod opis uczen_id klasa_id ksiazka_id kategoria_id Od zdarzenia do słowników: wypożyczenie → uczeń → klasa oraz wypożyczenie → książka → kategoria.
Pięciotabelowy raport zaczyna się od tabeli zdarzeń. Każde połączenie prowadzi do kolejnej tabeli słownikowej, aż w jednym wierszu znajdą się wszystkie potrzebne nazwy.
Kolumna raportu Skąd pochodzi Przez jakie połączenie
nazwisko ucznia uczniowie.nazwisko wypozyczenia.uczen_id = uczniowie.id
nazwa klasy klasy.nazwa uczniowie.klasa_id = klasy.id
tytuł książki ksiazki.tytul wypozyczenia.ksiazka_id = ksiazki.id
nazwa kategorii kategorie.nazwa ksiazki.kategoria_id = kategorie.id
Uwaga na mnożenie wierszy. Jeśli do raportu dołączysz tabelę ksiazki_autorzy, książka z dwoma autorami pojawi się dwa razy. Wtedy COUNT(*) policzy autorów, a nie książki. W MySQL do liczenia unikalnych książek możesz użyć COUNT(DISTINCT ks.id); w edytorze kursu policz książki w zapytaniu bez dołączania autorów. Sumy kar również wymagają starannie dobranych kolumn. Zawsze sprawdź, czy dodatkowe połączenie nie zmienia ziarna raportu.

Przykłady z życia

1. Zebranie z rodzicami. Wychowawca chce jednym raportem pokazać uczniów, ich klasy i liczbę wypożyczonych książek. Bez łączenia tabel musiałby otwierać kilka arkuszy i przepisywać dane ręcznie. Jedno zapytanie z JOIN i GROUP BY daje gotową tabelę do wydruku.

2. Raport sprzedaży. Firma analizuje sprzedaż według kategorii produktów i regionów. Tabele zamówień, pozycji, produktów i regionów łączy się po kluczach, a następnie grupuje po dwóch wymiarach. To ten sam schemat co raport klas i statusów wypożyczeń.

3. Turniej szkolny. Tabela meczów wskazuje drużyny i sędziów. Raport „punkty według drużyny i rundy” wymaga połączenia meczów z drużynami oraz grupowania po dwóch kolumnach. Bez JOIN widzielibyśmy tylko numery drużyn, a nie ich nazwy.

Ekonomia: analityk biznesowy mówi o „ziarnie raportu” — o tym, co opisuje jeden wiersz. W raporcie wypożyczeń ziarnem jest jedno wypożyczenie, dopóki nie dołączymy autorów. Dodanie tabeli autorów zmienia ziarno na parę książka–autor, więc sumy trzeba liczyć ostrożnie. To pojęcie wraca w każdym raporcie przekrojowym.

Jak to się łączy…

W module 04 nauczyłeś się grupować jedną tabelę, a w poprzednich sekcjach łączyć tabele. Tutaj oba narzędzia pracują razem. W module 06 zobaczysz podzapytania i widoki, które potrafią zapisać taki raport na stałe. W module 08 raporty połączysz z funkcjami i bezpieczeństwem, a w module 09 wykonasz pełne zadanie egzaminacyjne.

Geografia: raport „liczba szkół według gminy i typu” łączy tabelę szkół z gminami i słownikiem typów. Grupowanie po dwóch kolumnach daje tabelę krzyżową, z której widać, gdzie brakuje danego typu placówki. To dokładnie ten sam mechanizm co klasy i statusy wypożyczeń.

Zadanie transferowe 2 — raport wypożyczeń według kategorii

Biblioteka chce raportu, który pokaże dla każdej kategorii liczbę wypożyczeń i sumę kar. Uwzględnij tylko kategorie z co najmniej pięcioma wypożyczeniami i posortuj wynik malejąco po sumie kar, a przy równych sumach — malejąco po liczbie wypożyczeń. Napisz zapytanie z połączeniem trzech tabel i wyjaśnij, dlaczego nie wystarczy samo GROUP BY na tabeli wypozyczenia.

Pokaż przykładowe rozwiązanie i kryteria

Przykład: SELECT kat.nazwa AS kategoria, COUNT(w.id) AS wypozyczenia, SUM(w.kara) AS suma_kar FROM kategorie kat JOIN ksiazki ks ON kat.id = ks.kategoria_id JOIN wypozyczenia w ON ks.id = w.ksiazka_id GROUP BY kat.nazwa HAVING COUNT(w.id) >= 5 ORDER BY suma_kar DESC, wypozyczenia DESC; Tabela wypożyczeń nie zna nazwy kategorii, więc trzeba dołączyć książki i kategorie. Dopiero po połączeniu można grupować po nazwie kategorii.

Kryteria: (1) połączenia — użyto tabel kategorie, ksiazki i wypozyczenia po właściwych kluczach; (2) agregaty — policzono liczbę wypożyczeń i sumę kar; (3) filtr — HAVING COUNT(w.id) >= 5 działa na grupach; (4) wynik — zastosowano dwa poziomy sortowania i czytelne aliasy.

7. W raporcie wypożyczeń chcesz dołączyć nazwę klasy. Po jakich kolumnach połączysz tabele klasy i uczniowie?
7. W raporcie wypożyczeń chcesz dołączyć nazwę klasy. Po jakich kolumnach połączysz tabele klasy i uczniowie?
8. Raport ma pokazać liczbę wypożyczeń w każdej kategorii. Po czym należy grupować?
8. Raport ma pokazać liczbę wypożyczeń w każdej kategorii. Po czym należy grupować?
9. Dlaczego dołączenie tabeli ksiazki_autorzy może zwiększyć liczbę wierszy raportu książek?
9. Dlaczego dołączenie tabeli ksiazki_autorzy może zwiększyć liczbę wierszy raportu książek?

Ćwiczenia SQL

Zadania do samodzielnego wykonania w edytorze SQL.