Wyobraź sobie, że chcesz zapytać:
„Pokaż wszystkich klientów, którzy wydali więcej niż średnia wartość zamówienia w sklepie.”
Żeby to zrobić, potrzebujesz dwóch zapytań:
- jedno, które obliczy średnią wartość zamówienia,
- drugie, które wybierze klientów — i porówna ich wyniki do tej średniej.
To właśnie przykład podzapytania – czyli zapytania w zapytaniu.
1. Co to jest podzapytanie?
Podzapytanie (ang. subquery) to zapytanie SQL wstawione w innym zapytaniu.
Działa jak „mini-zapytanie”, które dostarcza dane do zapytania głównego.
Najczęściej pojawia się w klauzulach:
WHERE,FROM,SELECT.
Podzapytanie jest wykonywane najpierw, a jego wynik przekazywany jest do zapytania nadrzędnego.
2. Podstawowa składnia
SELECT kolumny
FROM tabela
WHERE kolumna OPERATOR (SELECT kolumny FROM inna_tabela WHERE warunek);
Operator może być np.:
=– dokładne dopasowanie,>lub<– porównanie,IN– sprawdzenie, czy wartość występuje w zestawie,ANY,ALL,EXISTS– zaawansowane warunki logiczne.
3. Przykłady na bazie sklep_muzyczny
a) Klienci, którzy wydali więcej niż średnia wszystkich zakupów
SELECT k.imie, k.nazwisko, SUM(z.ilosc * p.cena) AS wartosc
FROM Klienci k
JOIN Zamowienia z ON k.id_klienta = z.id_klienta
JOIN Produkty p ON z.id_produktu = p.id_produktu
GROUP BY k.imie, k.nazwisko
HAVING wartosc > (
SELECT AVG(z2.ilosc * p2.cena)
FROM Zamowienia z2
JOIN Produkty p2 ON z2.id_produktu = p2.id_produktu
);
Wewnątrz HAVING znajduje się podzapytanie, które oblicza średnią wartość wszystkich zakupów.
Zapytanie główne wybiera tylko tych klientów, którzy wydali więcej niż ta średnia.
b) Produkty droższe niż średnia cena wszystkich produktów
SELECT nazwa, cena
FROM Produkty
WHERE cena > (SELECT AVG(cena) FROM Produkty);
Podzapytanie (SELECT AVG(cena) FROM Produkty) zwraca jedną wartość – średnią cenę.
Główne zapytanie porównuje do niej każdą cenę produktu.
c) Produkty kupione przez klienta o nazwisku „Kowalski”
SELECT nazwa
FROM Produkty
WHERE id_produktu IN (
SELECT id_produktu
FROM Zamowienia z
JOIN Klienci k ON z.id_klienta = k.id_klienta
WHERE k.nazwisko = 'Kowalski'
);
Podzapytanie znajduje id_produktu z zamówień Kowalskiego,
a główne zapytanie wypisuje ich nazwy.
d) Klienci, którzy nie złożyli żadnego zamówienia
SELECT imie, nazwisko
FROM Klienci
WHERE id_klienta NOT IN (
SELECT id_klienta FROM Zamowienia
);
Podzapytanie tworzy listę wszystkich klientów, którzy coś zamówili.
Zapytanie główne wybiera tych, których nie ma na tej liście.
e) Produkt z najwyższą ceną (bez użycia MAX)
SELECT nazwa, cena
FROM Produkty
WHERE cena = (
SELECT cena FROM Produkty ORDER BY cena DESC LIMIT 1
);
Podzapytanie znajduje największą cenę,
a główne zapytanie pokazuje produkt, który ją ma.
4. Podzapytania w klauzuli FROM
Podzapytanie może działać jak tymczasowa tabela.
Przykład:
Oblicz średnią wartość zamówienia dla każdego klienta i pokaż tylko tych, których wynik przekracza 500 zł.
SELECT imie, nazwisko, wartosc
FROM (
SELECT k.imie, k.nazwisko, SUM(z.ilosc * p.cena) AS wartosc
FROM Klienci k
JOIN Zamowienia z ON k.id_klienta = z.id_klienta
JOIN Produkty p ON z.id_produktu = p.id_produktu
GROUP BY k.imie, k.nazwisko
) AS podsumowanie
WHERE wartosc > 500;
Wewnętrzne zapytanie tworzy tabelę podsumowanie, a zewnętrzne wybiera z niej dane według warunku.
5. Podzapytania w klauzuli SELECT
Czasem chcemy dodać do wyników dodatkową informację obliczoną dynamicznie.
Przykład:
Dla każdego produktu pokaż średnią cenę wszystkich produktów (dla porównania):
SELECT nazwa, cena,
(SELECT AVG(cena) FROM Produkty) AS srednia_cena
FROM Produkty;
Każdy wiersz będzie zawierał swoją cenę i średnią cenę wszystkich produktów.
6. Rodzaje podzapytań
| Rodzaj | Wynik | Użycie |
|---|---|---|
| Jednowartościowe (scalar) | Zwraca jedną wartość | WHERE cena > (SELECT AVG(cena) FROM Produkty) |
| Wielowartościowe (IN) | Zwraca wiele wartości | WHERE id IN (SELECT id_klienta FROM Zamowienia) |
| Zagnieżdżone | Wewnątrz innych podzapytań | SELECT ... WHERE x IN (SELECT ... WHERE y IN (...)) |
| W klauzuli FROM | Działa jak tymczasowa tabela | FROM (SELECT ...) AS tymczasowa |
7. Zadania praktyczne
Zadanie 1 – ceny powyżej średniej
Wyświetl wszystkie produkty, których cena jest większa niż średnia cena wszystkich produktów.
Zadanie 2 – klienci aktywni
Wyświetl imiona i nazwiska klientów, którzy złożyli zamówienia (czyli ich id_klienta znajduje się w tabeli Zamowienia).
Zadanie 3 – klienci bez zamówień
Wyświetl imiona i nazwiska klientów, którzy nie złożyli żadnego zamówienia (użyj NOT IN i podzapytania).
Zadanie 4 – najlepsi klienci
Wyświetl klientów, których suma zakupów przekracza średnią wszystkich sum zakupów.
Zadanie 5 – porównanie produktów
Dla każdego produktu pokaż jego cenę oraz średnią cenę wszystkich produktów (jako nową kolumnę srednia_cena).
Zadanie 6 – dla ambitnych
Pokaż nazwę najdroższego produktu w każdej kategorii (użyj podzapytania w klauzuli WHERE).
8. Typowe błędy uczniów
❌ Zapomniany nawias w podzapytaniu
❌ Użycie = zamiast IN przy wielu wynikach
❌ Brak aliasu przy podzapytaniu w FROM
❌ Mylenie kolejności wykonania (najpierw wykonuje się podzapytanie!)
9. Podsumowanie
| Klauzula | Zastosowanie podzapytania | Przykład |
|---|---|---|
| WHERE | filtrowanie danych | WHERE cena > (SELECT AVG(cena) FROM Produkty) |
| IN / NOT IN | sprawdzanie listy wartości | WHERE id IN (SELECT id_klienta FROM Zamowienia) |
| FROM | tymczasowa tabela | FROM (SELECT ...) AS T |
| SELECT | dodatkowe kolumny z obliczeniami | SELECT cena, (SELECT AVG(cena) FROM Produkty) |
Podzapytania to potężne narzędzie, które pozwala łączyć analizę danych z logiką programowania.
Dzięki nim możesz pisać jedno zapytanie, które robi kilka rzeczy naraz — bez konieczności tworzenia nowych tabel czy procedur.
To także ważny element egzaminu INF.03, gdzie często trzeba stworzyć raport oparty o dane z kilku tabel z warunkami i obliczeniami.

