SQL: wyszukiwanie
🎯 Po co Ci to?
Kwerendy z kreatora (12.3) są wygodne, ale mają sufit — a pod nimi, generowany automatycznie, czai się SQL: język, którym mówi się do niemal każdej bazy relacyjnej świata od lat 70. XX wieku. SQL jest jedną z najbardziej wpływowych i najtrwalszych technologii w historii informatyki — banki, rządy, sklepy, aplikacje, które ma w kieszeni pół planety, wszystkie „rozmawiają" ze swoimi bazami po SQL. A jego piękno polega na tym, że jest deklaratywny: mówisz, CO chcesz dostać, nie JAK to policzyć — baza sama dobiera algorytm (wyszukiwanie binarne? hasz? złączenie?). Rozszerzona podstawa wymaga SQL wprost, matura go sprawdza — a Ty poznasz go od najważniejszej strony: wydobywania danych.
✅ Czego się nauczysz
Po tej jednostce potrafisz:
- napisać zapytanie SELECT z wyborem pól, filtrem WHERE i sortowaniem ORDER BY;
- złączyć dwie tabele przez JOIN po kluczach;
- policzyć agregaty (COUNT, SUM, AVG) z grupowaniem GROUP BY.
🔁 Przypomnij sobie
Z 12.3: kwerenda, złączenie po kluczach; z 11.6: grupowanie i agregacja (GROUP BY to przestawna w kodzie); z 3.2: warunki logiczne (WHERE to if na rekordach).
📘 Wyjaśnienie
SELECT — szkielet zapytania. Podstawowa struktura: co wybrać, skąd, pod jakim warunkiem, w jakiej kolejności:
SELECT tytuł, autor -- które pola (kolumny) chcę
FROM ksiazki -- z której tabeli
WHERE autor = 'Prus' -- warunek (które rekordy) — jak filtr/if
ORDER BY tytuł; -- sortowanie wyniku
Czyta się to niemal po angielsku: „wybierz tytuł i autora z książek, gdzie autor to Prus, uporządkuj po tytule". To jest deklaratywność: opisałeś wynik, nie algorytm. Baza sama zdecyduje, czy przeszukać liniowo, czy użyć indeksu (o tym niżej). SELECT * wybiera wszystkie pola; WHERE przyjmuje warunki jak z 3.2 (>, <, =, AND, OR, NOT), a także LIKE do wzorców tekstowych (WHERE tytuł LIKE 'L%' — tytuły na L).
JOIN — złączenie tabel. Pytanie z wielu tabel (12.3) w SQL to JOIN — dopasowanie po kluczach:
SELECT klienci.nazwisko, ksiazki.tytuł, wypozyczenia.data
FROM wypozyczenia
JOIN klienci ON wypozyczenia.klient_id = klienci.id
JOIN ksiazki ON wypozyczenia.ksiazka_id = ksiazki.id;
Warunek ON ... = ... to dokładnie „klucz obcy = klucz główny" z 12.2 — sedno złączenia. Wynik: jeden wiersz na wypożyczenie, z nazwiskiem, tytułem i datą sklejonymi z trzech tabel. To jest ten moment, w którym rozbite dane wracają jako całość — deklaratywnie, jedną komendą.
Agregaty i GROUP BY. Pytania „ile", „suma", „średnia" — z grupowaniem:
SELECT klient_id, COUNT(*) AS liczba_ksiazek
FROM wypozyczenia
GROUP BY klient_id; -- grupuj po kliencie, policz w każdej grupie
COUNT(*) liczy rekordy w grupie, SUM(pole) sumuje, AVG(pole) uśrednia — funkcje agregujące z 11.3, a GROUP BY to serce tabeli przestawnej (11.6!) zapisane słowem. To zapytanie zwraca liczbę wypożyczeń każdego klienta — jeden wiersz na grupę. (Chcesz filtrować grupy, np. „klienci z >5 wypożyczeń"? Służy do tego HAVING — jak WHERE, ale dla grup.)
Skąd szybkość? Baza z milionem rekordów odpowiada na WHERE nazwisko = 'Kowalska' w milisekundy — nie przez przeglądanie liniowe (6.1: byłoby wolne), lecz przez indeks: dodatkową strukturę (posortowane drzewo albo tablicę haszującą) pozwalającą znaleźć rekord bez oglądania wszystkich. Wyszukiwanie binarne (6.2) i haszowanie (5.6) — algorytmy z części II — to sekret, dzięki któremu bazy są szybkie. Deklarujesz CO chcesz, a baza używa najszybszego algorytmu, jaki ma. Twoja wiedza z działów 5–6 właśnie wyjaśniła, czemu logowanie trwa mgnienie, a nie minutę.
💭 Pomyśl: Zapytanie
SELECT nazwisko FROM klienci WHERE telefon = '501-234-567'. Bez indeksu na kolumnie telefon baza z milionem klientów robi to w... ile operacji? A z indeksem? (Odwołaj się do działu 6.)
Sprawdź odpowiedź
Bez indeksu: przeszukiwanie liniowe (6.1) — do miliona porównań, bo telefon może być gdziekolwiek. Z indeksem na kolumnie telefon: wyszukiwanie binarne w posortowanym indeksie (6.2) — ~20 porównań ($\log_2 10^6$), albo jeszcze szybciej przez hasz (5.6) — kilka. Różnica: milion kontra dwadzieścia, czyli mgnienie kontra zauważalna zwłoka przy każdym zapytaniu. Dlatego pola, po których się często szuka (loginy, numery, klucze), indeksuje się — to inwestycja „posortuj raz, szukaj szybko wiele razy" z 6.2, wbudowana w bazę. Projektant bazy decyduje, co indeksować, ważąc szybkość odczytu przeciw kosztowi utrzymania indeksu przy zapisach.
🐞 Znajdź błąd
Zapytanie miało dać nazwiska klientów i tytuły ich książek, ale zwraca miliony wierszy (baza ma tysiąc klientów i tysiąc książek):
SELECT klienci.nazwisko, ksiazki.tytuł
FROM klienci, ksiazki;
Co się stało?
Sprawdź odpowiedź
Brak warunku złączenia! FROM klienci, ksiazki bez JOIN ... ON (albo WHERE) daje iloczyn kartezjański — każdy klient sparowany z każdą książką: 1000 × 1000 = milion bezsensownych wierszy (Kowalska „połączona" z każdą książką bazy). To pułapka z 12.3 (złączenie za duże) w składni SQL. Poprawnie trzeba przejść przez WYPOŻYCZENIA i dać warunki dopasowania kluczy (jak w JOIN wyżej). Iloczyn kartezjański to klasyczny błąd początkujących w SQL — objawia się absurdalnie wielką liczbą wyników. Zawsze sprawdzaj, czy liczba wierszy ma sens.
🛠️ Teraz Ty
Na papierze (albo w darmowej bazie testowej — jest ich wiele online) napisz SQL dla bazy z 12.2: (a) tytuły wszystkich książek Dostojewskiego; (b) nazwiska klientów i tytuły, które wypożyczyli (JOIN); (c) liczba wypożyczeń każdego klienta (GROUP BY); (d) klienci, którzy wypożyczyli więcej niż jedną książkę (GROUP BY + HAVING). Sprawdzaj liczby wierszy — czy mają sens?
📐 Definicje tej lekcji
- SQL — deklaratywny język zapytań do baz relacyjnych; opisujesz wynik, baza dobiera algorytm.
- SELECT ... FROM ... WHERE ... ORDER BY — wybór pól, tabela, filtr rekordów, sortowanie.
- JOIN ... ON — złączenie tabel po kluczach; GROUP BY — grupowanie do agregatów (COUNT/SUM/AVG).
- Indeks — struktura (drzewo/hasz) przyspieszająca wyszukiwanie; sekret szybkości bazy (6.2, 5.6).
📌 Najważniejsze w pigułce
- SQL jest deklaratywny: mówisz CO, baza wybiera JAK (najszybszy algorytm z arsenału części II).
- JOIN ... ON łączy tabele po „klucz obcy = klucz główny"; brak warunku = iloczyn kartezjański.
- GROUP BY = przestawna w kodzie; indeksy (binarne/hasz) dają odpowiedzi w milisekundy.
🎒 Zadania
- Napisz SQL: tytuły książek wypożyczonych po 2026-02-01, posortowane wg daty malejąco. Które tabele i warunki?
Wskazówka i odpowiedź
SELECT ksiazki.tytuł, wypozyczenia.data FROM wypozyczenia JOIN ksiazki ON wypozyczenia.ksiazka_id = ksiazki.id WHERE wypozyczenia.data > '2026-02-01' ORDER BY wypozyczenia.data DESC; (DESC = malejąco). JOIN tylko z KSIĄŻKI (klienci niepotrzebni — nie pytamy o nich); WHERE filtruje daty; ORDER BY porządkuje. Struktura SELECT-FROM-JOIN-WHERE-ORDER BY jest zawsze ta sama — składasz z klocków wg pytania.
- Przetłumacz na SQL i na polski:
SELECT autor, COUNT(*) FROM ksiazki GROUP BY autor ORDER BY COUNT(*) DESC;. Co zwraca i do czego to przydatne?
Wskazówka i odpowiedź
„Dla każdego autora policz, ile ma książek w bazie, i pokaż od najliczniejszego." Zwraca ranking autorów wg liczby tytułów. Przydatne: analiza księgozbioru, wykrycie „kto dominuje". To przestawna z 11.6 (autor w wierszach, licznik w wartościach, sortowanie malejąco) — jedną linijką SQL. Rozpoznawanie „to jest przestawna / to jest GROUP BY" w obu światach to dowód, że rozumiesz mechanizm, nie tylko składnię.
- Baza logowań serwisu ma 50 mln rekordów. Zapytanie
WHERE login = 'anna'bez indeksu trwa 8 sekund, z indeksem — 3 milisekundy. Wyjaśnij tę różnicę liczbami z działu 6 i powiedz, jaki jest koszt założenia indeksu.
Wskazówka i odpowiedź
Bez indeksu: liniowe przeglądanie 50 mln rekordów (6.1). Z indeksem: binarne (~$\log_2(5\cdot10^7) \approx 26$ porównań) albo hasz (kilka) — stąd tysiące razy szybciej, 8 s → 3 ms. Koszt indeksu: zajmuje pamięć (dodatkowa struktura) i spowalnia zapisy (przy każdym dodaniu/zmianie rekordu trzeba zaktualizować też indeks). Dlatego indeksuje się pola często wyszukiwane (login, klucze), a nie wszystkie — to znajomy handel „przygotowanie za szybkość zapytań" (6.2) i „pamięć za czas" (6.6), tu w decyzji projektanta bazy. Nadmiar indeksów szkodzi tak samo jak ich brak.
🔍 Sprawdź, czy umiesz
- Napisać SELECT z WHERE i ORDER BY oraz JOIN dwóch tabel.
- Zbudować agregat z GROUP BY i rozpoznać w nim przestawną.
- Wyjaśnić rolę indeksu i połączyć szybkość bazy z algorytmami z części II.