Podzapytanie (ang. subquery) to zapytanie SQL zagnieżdżone wewnątrz innego zapytania — zwykle w klauzuli WHERE, FROM, SELECT albo HAVING. Najpierw wykonuje się podzapytanie wewnętrzne, a jego wynik (pojedyncza wartość, lista wartości albo cała tabela tymczasowa) staje się wejściem dla zapytania nadrzędnego. Dzięki temu rozbijasz jeden problem na warstwy: zamiast kombinować z jednym monstrualnym zapytaniem, zadajesz pytanie pomocnicze, a potem korzystasz z odpowiedzi.
Jak to działa
Podzapytania dzielimy z grubsza na dwa typy. Niezależne (non-correlated) wykonują się raz, niezależnie od zapytania zewnętrznego — silnik liczy wynik i go podstawia. Skorelowane (correlated) odwołują się do kolumn z zapytania nadrzędnego, więc wykonują się dla każdego wiersza zewnętrznego — potężne, ale potrafią zarżnąć wydajność.
Liczy się też, ile danych podzapytanie zwraca. Jeśli pojedynczą wartość, możesz porównać ją operatorem (=, >). Jeśli listę, użyjesz IN, ANY albo ALL. Jeśli całą tabelę — wstawisz ją do FROM jako tzw. derived table.
Przykład z praktyki
Masz w PostgreSQL tabele employees i chcesz wyciągnąć osoby zarabiające powyżej średniej w firmie. Bez podzapytania ani rusz, bo najpierw musisz policzyć tę średnią:
SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
Wewnętrzne SELECT AVG(salary) zwraca jedną liczbę, a zewnętrzne porównuje do niej każdy wiersz. Klasyczny przykład podzapytania zwracającego listę to WHERE department_id IN (SELECT id FROM departments WHERE active = true).
Na co uważać
- Podzapytanie skalarne zwracające więcej niż jeden wiersz — przy operatorze
=dostaniesz błąd w stylu „more than one row returned”. UżyjINalbo ogranicz wynik. - NULL w połączeniu z
NOT IN— jeśli podzapytanie zwróci choć jedenNULL, całeNOT INpotrafi nie zwrócić nic. To klasyczna pułapka; bezpieczniej sięgnąć poNOT EXISTS. - Wydajność — skorelowane podzapytanie w
SELECTwykonywane milion razy to prosta droga do zawieszki. Często da się je przepisać naJOIN, który optymalizator obsłuży lepiej.
Mit, że „podzapytanie jest zawsze wolniejsze od JOIN”, jest nieprawdziwy — nowoczesne optymalizatory (PostgreSQL, MySQL 8+) potrafią je spłaszczyć. Pisz tak, żeby było czytelnie, a mierz dopiero, gdy realnie boli.
Pojęcia powiązane
Warto znać: JOIN, CTE (Common Table Expression, czyli WITH), operatory EXISTS i IN, derived table, widok (VIEW) oraz plan zapytania (EXPLAIN).