Wyobraź sobie, że pracujesz jako analityk na uniwersytecie (robimy przecież bazę danych dla uczelni, pamiętasz?). Poproszono cię, żebyś nie tylko wyświetlił studentów i ich oceny, ale też dodał do tabeli kolumnę z maksymalną oceną w grupie, żeby łatwo porównywać wyniki. Jak to ogarnąć? Jasne, z pomocą subquery w SELECT!
Subquery w SELECT pozwala liczyć wartości bezpośrednio podczas wykonywania głównego zapytania. To jest mega, bo możesz łączyć agregaty, złożone filtry i nawet inne zbiory danych w jednym zapytaniu.
Podstawy zagnieżdżonych zapytań w SELECT
Subquery w SELECT działa dokładnie tak, jak brzmi: wrzucasz wynik jednego SELECT do środka drugiego. Dzięki temu możesz policzyć dodatkowe wartości dla każdego wiersza wyniku.
Prosty przykład. Załóżmy, że mamy tabelę students o takiej strukturze:
| student_id | name | group_id |
|---|---|---|
| 1 | Linda | 101 |
| 2 | Otto | 102 |
| 3 | Anna | 101 |
I tabelę grades:
| grade_id | student_id | grade |
|---|---|---|
| 1 | 1 | 5 |
| 2 | 1 | 4 |
| 3 | 2 | 3 |
| 4 | 3 | 5 |
| 5 | 3 | 4 |
Przykład 1: Dodanie maksymalnej oceny w grupie
Zadanie: wyświetlić imiona studentów, ich oceny i maksymalną ocenę w grupie, żeby było widać, jak bardzo wyniki każdego różnią się od najlepszych w grupie.
Kod SQL:
SELECT
s.name AS student_name,
g.grade AS student_grade,
(
SELECT MAX(grade) -- to zapytanie zwraca tylko jedną wartość
FROM grades
INNER JOIN students ON grades.student_id = students.student_id
WHERE students.group_id = s.group_id
) AS max_group_grade
FROM
students s
INNER JOIN
grades g ON s.student_id = g.student_id;
Co tu się dzieje:
- Dla każdego studenta pobieramy jego imię i ocenę (
s.name,g.grade). SELECT MAX(grade)— to subquery, które zwraca maksymalną ocenę w grupie studenta.- Subquery wykonuje się dla każdego wiersza głównego zapytania i używa warunku
WHERE students.group_id = s.group_id, żeby ograniczyć wybór do jednej grupy.
Przykład 2: Średnia ocena w grupie
Chcesz być jeszcze bardziej pomocny dla analityków? Dodajmy do wyniku nie tylko maksymalną, ale też średnią ocenę w grupie.
Kod SQL:
SELECT
s.name AS student_name,
g.grade AS student_grade,
(
SELECT AVG(grade)
FROM grades
INNER JOIN students ON grades.student_id = students.student_id
WHERE students.group_id = s.group_id
) AS avg_group_grade
FROM
students s
INNER JOIN
grades g ON s.student_id = g.student_id;
Teraz:
- Zamiast
MAX()używamyAVG(), żeby policzyć średnią ocenę w grupie. - Dostajemy "na żywo" analizę danych.
Ograniczenia i wskazówki
Subquery w SELECT są mocne, ale trzeba z nimi uważać:
- Wydajność. Każde subquery wykonuje się dla każdego wiersza głównego zapytania. To może spowolnić SQL, jeśli tabele są duże. Na przykład, jeśli masz 1000 studentów, subquery wykona się 1000 razy!
- Indeksy. Żeby przyspieszyć takie zapytania, dobrze zindeksuj kolumny używane w warunkach
WHEREsubquery. - Czytelność. Unikaj zbyt dużego zagnieżdżenia. Jeśli subquery robi się za bardzo skomplikowane, pomyśl o przeniesieniu ich do
FROMalbo użyciu tymczasowych tabel.
Przykłady użycia
Zobaczmy jeszcze kilka ciekawych case'ów.
Przykład 3: Liczba kursów każdego studenta
Wyświetlamy tabelę, gdzie dla każdego studenta pokazujemy liczbę kursów, na które jest zapisany. Tabela enrollments jest powiązana ze studentami przez student_id:
| student_id | course_id |
|---|---|
| 1 | 201 |
| 1 | 202 |
| 2 | 201 |
| 3 | 203 |
Kod SQL:
SELECT
s.name AS student_name,
(
SELECT COUNT(*)
FROM enrollments
WHERE enrollments.student_id = s.student_id
) AS course_count
FROM
students s;
Tutaj subquery liczy ilość wpisów w tabeli enrollments dla każdego studenta.
Przykład 4: Flaga "prymus" dla każdego studenta
Pokażemy, czy student jest prymusem. Niech kryterium prymusa będzie to, że wszystkie jego oceny to 5.
Kod SQL:
SELECT
s.name AS student_name,
(
SELECT CASE
WHEN MIN(g.grade) = 5 THEN 'Prymus'
ELSE 'Nie prymus'
END
FROM grades g
WHERE g.student_id = s.student_id
) AS status
FROM
students s;
Tu używamy zagnieżdżonego CASE, żeby nadać status "Prymus" tylko tym studentom, którzy mają wszystkie oceny równe 5.
Optymalizacja subquery w SELECT
Już wspomnieliśmy, że wydajność może być problemem. Oto kilka tipów, jak ją poprawić:
- Używaj indeksów. Jeśli subquery filtrują dane, upewnij się, że na używanych kolumnach są indeksy.
- Cache'uj wyniki. Czasem warto wynieść subquery do widoków (
VIEW) albo tymczasowych tabel. - Mniej zagnieżdżenia. Nie przesadzaj z ilością zagnieżdżeń, jeśli da się to zrobić prościej.
Subquery w SELECT otwierają masę możliwości do liczenia i analizy danych. Chociaż mogą być zasobożerne, dobrze zoptymalizowane sprawiają, że SQL jest dużo bardziej wyrazisty i elastyczny. Więc nie bój się eksperymentować i znajdować swoje sposoby na ulepszanie zapytań!
GO TO FULL VERSION