Podzapytanie

Zapytanie zagnieżdżone wewnątrz innego zapytania. Wynik podzapytania jest używany jako dane wejściowe dla zapytania nadrzędnego.

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żyj IN albo ogranicz wynik.
  • NULL w połączeniu z NOT IN — jeśli podzapytanie zwróci choć jeden NULL, całe NOT IN potrafi nie zwrócić nic. To klasyczna pułapka; bezpieczniej sięgnąć po NOT EXISTS.
  • Wydajność — skorelowane podzapytanie w SELECT wykonywane milion razy to prosta droga do zawieszki. Często da się je przepisać na JOIN, 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).