Wyobraź sobie, że każda tabela w twojej bazie to kawałek jednej wielkiej układanki. Tabela studentów wie, kto się uczy, tabela kursów — czego uczą, a tabela zapisów — kto na co jest zapisany. Ale osobno te kawałki nie mówią zbyt wiele. Chcesz zobaczyć cały obrazek? Trzeba je połączyć — i tu na scenę wchodzi wielokrotny JOIN.
W realnym życiu dane są często zorganizowane w powiązane tabele, żeby zachować strukturę i nie powielać informacji. Na przykład, w naszej bazie uniwersytetu mamy takie tabele:
students— dane o studentach.enrollments— info o zapisach studentów na kursy.courses— info o kursach.
Jeśli chcemy dostać pełną listę studentów, ich kursów i nauczycieli, trzeba połączyć trzy tabele używając JOIN.
Kolejność wykonywania JOIN
Przy użyciu kilku JOIN, PostgreSQL przetwarza je od lewej do prawej. To znaczy, że najpierw łączone są dwie pierwsze tabele, potem wynik jest łączony z trzecią tabelą i tak dalej.
Przykład:
SELECT *
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;
- Najpierw łączone są tabele
studentsienrollmentspo kolumniestudents.id = enrollments.student_id. - Wynik pierwszego połączenia jest używany do połączenia z tabelą
coursespo kolumnieenrollments.course_id = courses.id.
Kolejność wykonywania jest szczególnie ważna, gdy w zapytaniu biorą udział duże tabele. Zła struktura JOIN może mocno spowolnić działanie zapytania.
Przykład: Lista studentów, ich kursów i nauczycieli
Załóżmy, że mamy takie tabele z danymi:
Tabela students:
| id | name |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
Tabela courses:
| id | name | teacher |
|---|---|---|
| 101 | Mathematics | Ellen Moore |
| 102 | Physics | James Okoro |
| 103 | Computer Science | Nina Delgado |
Tabela enrollments:
| student_id | course_id |
|---|---|
| 1 | 101 |
| 1 | 103 |
| 2 | 102 |
| 3 | 101 |
Zapytanie:
SELECT
students.name AS student_name,
courses.name AS course_name,
courses.teacher AS teacher_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;
Wynik:
| student_name | course_name | teacher_name |
|---|---|---|
| Otto Song | Mathematics | Ellen Moore |
| Otto Song | Computer Science | Nina Delgado |
| Maria Chi | Physics | James Okoro |
| Alex Lin | Mathematics | Ellen Moore |
Filtrowanie w zapytaniach z wieloma JOIN
Możesz stosować warunki filtrowania do zapytań z JOIN, żeby ograniczyć ilość zwracanych danych i przyspieszyć wykonanie zapytania. Na przykład, jeśli chcesz wyświetlić tylko tych studentów, którzy uczą się na kursie "Mathematics":
SELECT
students.name AS student_name,
courses.name AS course_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id
WHERE courses.name = 'Mathematics';
Wynik:
| student_name | course_name |
|---|---|
| Otto Song | Mathematics |
| Alex Lin | Mathematics |
Optymalizacja zapytań z wieloma JOIN
Przy pracy z dużymi tabelami optymalizacja zapytań robi się mega ważna. Oto kilka tipów:
- Używaj indeksów
Indeksy pozwalają PostgreSQL działać szybciej, szczególnie przy łączeniu po kluczowych polach. Upewnij się, że na kolumnach student_id i course_id w tabeli enrollments są indeksy.
Przykład tworzenia indeksu:
CREATE INDEX idx_enrollments_student_id ON enrollments(student_id);
CREATE INDEX idx_enrollments_course_id ON enrollments(course_id);
Więcej o indeksach dowiesz się na kolejnych poziomach, ale już teraz warto o nich wspomnieć. Są bardzo często powiązane z JOIN.
- Filtruj dane na wczesnym etapie
Stosuj warunki WHERE, żeby zmniejszyć ilość przetwarzanych wierszy zanim wykonasz JOIN. Na przykład:
SELECT
students.name AS student_name,
courses.name AS course_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id
WHERE
courses.teacher = 'Ivan Pietrow';
- Minimalizuj ilość wierszy do połączenia
Zamiast łączyć wszystkie rekordy z dwóch tabel, spróbuj najpierw je przefiltrować podzapytaniami:
SELECT
students.name AS student_name,
courses.name AS course_name
FROM
(SELECT * FROM students WHERE id IN (1, 2)) sub_students
INNER JOIN enrollments ON sub_students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;
Więcej o zagnieżdżonych SELECT-ach dowiesz się już na następnym poziomie :P
Przykład trudniejszego połączenia: studenci, kursy i wydziały
Załóżmy, że dodajemy jeszcze jedną tabelę faculties:
Tabela faculties:
| id | name |
|---|---|
| 10 | Engineering |
| 20 | Natural Sciences |
Tabela courses zaktualizowana:
| id | name | teacher | faculty_id |
|---|---|---|---|
| 101 | Mathematics | Ellen Moore | 10 |
| 102 | Physics | James Okoro | 20 |
| 103 | Computer Science | Nina Delgado | 10 |
Żeby dostać listę studentów, kursów i wydziałów, dodajemy jeszcze jeden JOIN:
SELECT
students.name AS student_name,
courses.name AS course_name,
faculties.name AS faculty_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id
INNER JOIN faculties ON courses.faculty_id = faculties.id;
Wynik:
| student_name | course_name | faculty_name |
|---|---|---|
| Otto Song | Mathematics | Engineering |
| Otto Song | Computer Science | Engineering |
| Maria Chi | Physics | Natural Sciences |
| Alex Lin | Mathematics | Engineering |
SQL-zapytania z wieloma JOIN mogą być skomplikowane, ale pozwalają tworzyć mocne raporty i wyciągać wartościowe info. Jeśli dobrze je zoptymalizujesz i poukładasz, staną się twoim narzędziem do pracy z dużymi bazami danych.
GO TO FULL VERSION