Wskakujemy jeszcze głębiej do króliczej nory: zobaczmy, jak używać podzapytań w konstrukcji FROM. To jeden z najczęstszych trików SQL-developerów, bo pozwala tworzyć potężne tymczasowe tabele dokładnie "na miejscu" i używać ich tak, jakby istniały w bazie danych.
Wyobraź sobie, że robisz raport, który wymaga obliczeń, grupowania albo filtrowania danych, ale nie chcesz tworzyć dodatkowych tymczasowych tabel na serwerze. Co wtedy? Tu właśnie ratują nas podzapytania w FROM. Pozwalają one na:
- Tymczasowe łączenie danych albo ich agregowanie przed głównym zapytaniem.
- Tworzenie uporządkowanych zestawów danych "w locie".
- Zmniejszenie liczby operacji, wymagając od bazy minimalnego przechowywania danych pośrednich.
Podzapytania w FROM działają jak mini-tabele, które możesz wykorzystać w głównym zapytaniu. To trochę jak budowanie z klocków: szybko, elastycznie i bez zbędnych kosztów :)
Podstawy podzapytań w FROM
W podzapytaniach w FROM używamy podzapytań, żeby stworzyć tymczasową tabelę (albo podtabelę), która staje się częścią całego zapytania. Trzeba zrobić trzy kluczowe kroki:
- Napisać podzapytanie w konstrukcji
FROMw nawiasach okrągłych. - Przypisać alias (pseudonim) dla podzapytania.
- Używać tego aliasu tak, jakby to była normalna tabela.
Składnia
SELECT kolumny
FROM (
SELECT kolumny
FROM tabela
WHERE warunek
) AS pseudonim
WHERE zewnętrzny_warunek;
Brzmi groźnie? To lecimy z przykładami.
Przykład: Studenci i średnia ocena
Załóżmy, że mamy dwie tabele:
students (dane o studentach — ich imię i ID):
| student_id | student_name |
|---|---|
| 1 | Alex |
| 2 | Anna |
| 3 | Dan |
grades (dane o ocenach studentów):
| grade_id | student_id | grade |
|---|---|---|
| 1 | 1 | 80 |
| 2 | 1 | 85 |
| 3 | 2 | 90 |
| 4 | 3 | 70 |
| 5 | 3 | 75 |
Teraz zadanie: uzyskać listę studentów i ich średnią ocenę.
Możemy zacząć od prostego podzapytania, które liczy średnią ocenę każdego studenta, a potem użyć tego w głównym zapytaniu.
SELECT s.student_name, g.avg_grade
FROM (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g
JOIN students AS s ON s.student_id = g.student_id;
Wynik:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
| Dan | 72.5 |
Tymczasowe tabele "w locie"
Podzapytania w FROM są szczególnie przydatne, gdy musisz zrobić więcej niż jeden poziom przetwarzania danych. Na przykład, jeśli chcesz nie tylko uzyskać średnią ocenę, ale też policzyć maksymalną ocenę dla każdego studenta — wszystko w jednym zapytaniu.
SELECT g.student_id, g.avg_grade, g.max_grade
FROM (
SELECT student_id,
AVG(grade) AS avg_grade,
MAX(grade) AS max_grade
FROM grades
GROUP BY student_id
) AS g;
Wynik:
| student_id | avg_grade | max_grade |
|---|---|---|
| 1 | 82.5 | 85 |
| 2 | 90 | 90 |
| 3 | 72.5 | 75 |
Zwróć uwagę, że to działa jak pełnoprawna tymczasowa tabela ze swoimi kolumnami: avg_grade i max_grade.
Kiedy najlepiej używać podzapytań w FROM?
Dla danych zagregowanych. Jeśli chcesz najpierw zrobić obliczenia (np. policzyć średnią, sumy albo maksimum), a potem połączyć wyniki z innymi tabelami.
Do filtrowania danych. Gdy trzeba przefiltrować dane przed połączeniem z główną tabelą.
Do uproszczenia złożonych zapytań. Podzielenie trudnych zadań na etapy pomaga uniknąć chaosu.
Przykład: Raport o studentach z dwoma poziomami przetwarzania
Wyobraź sobie, że chcesz znaleźć studentów, którzy mają średnią ocenę powyżej 80. Zaczynamy od podzapytania, które liczy średnie oceny, a potem używamy go w filtrze.
SELECT s.student_name, g.avg_grade
FROM students AS s
JOIN (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g ON s.student_id = g.student_id
WHERE g.avg_grade > 80;
Wynik:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
Wskazówki i rekomendacje
Obowiązkowy alias. Zawsze nadaj alias podzapytaniu (np. AS g), bo inaczej PostgreSQL nie będzie wiedział, jak się odwołać do tej "tymczasowej tabeli".
Optymalizacja. Podzapytania w FROM mogą być wolniejsze niż zwykłe łączenia tabel (JOIN), szczególnie jeśli filtrujesz dane wewnątrz podzapytania.
Indeksowanie. Upewnij się, że pola używane do łączenia, indeksy i filtry są zoptymalizowane — to mocno wpływa na wydajność.
Przykład trudniejszego zapytania: kursy i liczba studentów
To teraz coś bardziej praktycznego. Wyobraź sobie, że mamy taką tabelę:
courses (lista kursów):
| course_id | course_name |
|---|---|
| 1 | SQL Basics |
| 2 | Python Basics |
I enrollments (zapisy studentów na kursy):
| student_id | course_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
Teraz chcemy się dowiedzieć, ilu studentów jest zapisanych na każdy kurs.
SELECT c.course_name, e.students_count
FROM courses AS c
JOIN (
SELECT course_id, COUNT(student_id) AS students_count
FROM enrollments
GROUP BY course_id
) AS e ON c.course_id = e.course_id;
Wynik:
| course_name | students_count |
|---|---|
| SQL Basics | 2 |
| Python Basics | 1 |
Mam nadzieję, że wykład Ci się spodobał... ale następny będzie jeszcze ciekawszy :)
GO TO FULL VERSION