CodeGym /Kursy /SQL SELF /Przykłady złożonych zapytań zagnieżdżonych: łączenie EXIS...

Przykłady złożonych zapytań zagnieżdżonych: łączenie EXISTS, IN, HAVING

SQL SELF
Poziom 14 , Lekcja 3
Dostępny

Przykłady złożonych zapytań zagnieżdżonych: łączenie EXISTS, IN, HAVING

Gratulacje, dotarliśmy do momentu, gdzie zaczyna się robić naprawdę ciekawie! Dzisiaj zobaczymy, jak łączyć różne typy podzapytań, żeby rozwiązywać bardziej złożone zadania. EXISTS, IN, HAVING — to właśnie ta trójka sprawi, że poczujesz się jak mag baz danych. Będziemy wyciągać dane z jednej tabeli, filtrować je na podstawie danych z innej, grupować, a potem jeszcze filtrować te grupy. A na dokładkę — ogarniemy, jakie triki pomagają robić to szybciej i sprawniej.

Zacznijmy od postawienia jednego ogólnego zadania, które krok po kroku rozwiążemy w trakcie wykładu.

Opis zadania

Załóżmy, że mamy bazę danych uniwersytetu z trzema tabelami:

Tabela students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Tabela courses

id name
1 Matematyka
2 Programowanie
3 Filozofia

Tabela enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70

Musimy wybrać wszystkich studentów, którzy:

  1. Są zapisani przynajmniej na jeden kurs EXISTS.
  2. Nie mają oceny z przynajmniej jednego kursu, na który są zapisani IN.
  3. Należą do grup, gdzie średnia ocen jest wyższa niż 80 HAVING.

Rozwiązanie z użyciem EXISTS i IN

Krok 1: Sprawdzenie zapisanych studentów (EXISTS). Zaczynamy od najprostszego warunku. Musimy sprawdzić, którzy studenci są zapisani na przynajmniej jeden kurs. Do tego użyjemy EXISTS.

SELECT name
FROM students s
WHERE EXISTS (
  SELECT 1
  FROM enrollments e
  WHERE e.student_id = s.id
);
  1. Zewnętrzne zapytanie wybiera imiona z tabeli students.
  2. W podzapytaniu sprawdzamy, czy są wpisy w tabeli enrollments odpowiadające konkretnemu studentowi z zapytania zewnętrznego (WHERE e.student_id = s.id).
  3. SELECT 1 oznacza, że interesuje nas tylko istnienie wpisów, a nie ich zawartość.

Wynik:

name
Otto
Maria
Alex

Teraz już wiemy, którzy studenci są zapisani na kursy. Ale chcemy więcej. Chcemy przefiltrować ich po braku ocen.

Krok 2: Sprawdzenie braku oceny (IN + NULL). Teraz dodamy filtr: potrzebujemy tylko tych studentów, którzy mają przynajmniej jeden kurs bez oceny. Tu przydadzą się IN i znajomość pracy z NULL.

SELECT name
FROM students s
WHERE id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. W zapytaniu zewnętrznym wybieramy imiona studentów.
  2. Podzapytanie tworzy listę student_id z tabeli enrollments, gdzie grade IS NULL.

Wynik:

name
Otto

No i mamy — Otto to jedyny student, który ma kurs bez oceny. Ale to jeszcze nie koniec: musimy wziąć pod uwagę tylko te grupy, gdzie średnia ocen jest wyższa niż 80.

Rozwiązanie z użyciem HAVING

Krok 3: Grupowanie i filtrowanie z HAVING.

Teraz czas połączyć wszystko w całość. Musimy:

  1. Policzyć średnią ocenę dla każdej grupy.
  2. Przefiltrować grupy, gdzie średnia ocen jest wyższa niż 80.
  3. Wyświetlić studentów z tych grup, biorąc pod uwagę wcześniejsze warunki.
SELECT name
FROM students s
WHERE s.group_id IN (
  SELECT group_id
  FROM students
  JOIN enrollments ON students.id = enrollments.student_id
  WHERE grade IS NOT NULL
  GROUP BY group_id
  HAVING AVG(grade) > 80
)
AND id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. Zewnętrzne zapytanie wybiera imiona studentów, którzy spełniają wszystkie warunki.
  2. Pierwsze podzapytanie w WHERE zwraca listę group_id dla grup ze średnią oceną powyżej 80.
    • Łączymy students z enrollments, żeby dostać oceny.
    • Filtrujemy tylko te wpisy, gdzie grade IS NOT NULL.
    • Grupujemy dane po group_id.
    • Używamy HAVING do filtrowania grup.
  3. Drugie podzapytanie w WHERE sprawdza, czy student ma przynajmniej jeden kurs bez oceny.
  4. Obie części warunku są połączone przez AND.

Wynik:

name
Otto

Wyszło na to, że Otto to nie tylko jedyny student bez oceny, ale też należy do grupy, która może się pochwalić świetnymi wynikami.

Porównanie podejść: EXISTS vs IN

EXISTS najlepiej sprawdza się, gdy chcesz szybko sprawdzić, czy istnieją jakieś wpisy. Jest wydajny, bo zatrzymuje szukanie od razu po znalezieniu pierwszego wpisu. To szczególnie ważne przy dużych tabelach.

Z kolei IN jest przydatny, gdy skupiasz się na zawartości danych. Na przykład, gdy wyciągasz listę identyfikatorów (id) do dalszego filtrowania. Ale pamiętaj, że IN może być wolniejszy, jeśli podzapytanie zwraca dużo wartości.

Kiedy używać HAVING

Dla danych zagregowanych, gdzie musisz filtrować na podstawie wyników, HAVING to najlepszy wybór. Ale jeśli możesz przenieść warunek do WHERE (np. filtrowanie po kolumnie), to uprości zapytanie i przyspieszy jego wykonanie.

Pełny przykład

Dla utrwalenia ogarniemy jeszcze jeden przykład: wybierz grupy, gdzie przynajmniej jeden student ma ocenę poniżej 75, ale jednocześnie nie jest zapisany na kurs "Filozofia".

Przypominamy nasze tabele:

Tabela students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Tabela courses

id name
1 Matematyka
2 Programowanie
3 Filozofia

Tabela enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70
SELECT DISTINCT group_id
FROM students s
WHERE group_id IN (
  SELECT s.group_id
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.grade < 75
)
AND group_id NOT IN (
  SELECT s.group_id                                 -- podzapytanie 1-go poziomu
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.course_id = (
    SELECT id FROM courses WHERE name = 'Filozofia' -- podzapytanie 2-go poziomu :P
  )
);
  1. Pierwsze podzapytanie wybiera grupy, gdzie jest student z oceną poniżej 75.
  2. Drugie podzapytanie wyklucza grupy powiązane z kursem "Filozofia".
  3. Łączymy warunki przez IN i NOT IN, żeby dostać końcowy wynik.

Wynik:

group_id
101

Na ile to się przydaje?

W prawdziwym życiu takie podejścia ratują, gdy trzeba analizować złożone powiązania danych. Na przykład:

  • W analizie, żeby wyłapać "wyjątkowe" grupy klientów (VIP, problematyczni itd.).
  • W budowie systemów rekomendacyjnych, gdzie filtrujemy użytkownika po wielu kryteriach.
  • Na rozmowach o pracę, gdy poproszą cię o optymalizację trudnego zapytania SQL.

Ćwicz! To twoja droga do mistrzostwa.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION