No to czas pogadać o życiu. O tej stronie, której nie da się uniknąć: błędy. Łapanie, poprawianie i rozumienie błędów — to obowiązkowa część pracy z danymi. Zobaczmy, na jakie miny można wpaść przy pracy z JOIN w SQL i jak je ominąć.
Błąd 1: Pominięcie warunku łączenia — powstaje iloczyn kartezjański
Najczęstszy błąd — zapomnieć podać warunek łączenia, używając ON. Wtedy powstaje iloczyn kartezjański, gdzie każdy wiersz z pierwszej tabeli łączy się z każdym wierszem z drugiej. W efekcie dostajesz ogromną liczbę wierszy, które nie mają sensu i tylko mieszają w głowie.
Przykład. Załóżmy, że mamy takie tabele:
Studenci (students):
| student_id | name |
|---|---|
| 1 | Otto |
| 2 | Anna |
Kursy (courses):
| course_id | course_name |
|---|---|
| 101 | Matematyka |
| 102 | Historia |
Teraz napiszemy zapytanie, zapominając o ON:
SELECT *
FROM students
JOIN courses;
Wynik:
| student_id | name | course_id | course_name |
|---|---|---|---|
| 1 | Otto | 101 | Matematyka |
| 1 | Otto | 102 | Historia |
| 2 | Anna | 101 | Matematyka |
| 2 | Anna | 102 | Historia |
Nie wygląda to na prawdę, co? Ten koszmar to iloczyn kartezjański.
Jak naprawić: użyj ON, żeby wskazać, jak dane w tabelach są powiązane.
SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;
I tu pojawia się nowy rozdział błędów...
Ochrona przed głupotą
To tak częsty problem, że w PostgreSQL zabroniono używania JOIN bez ON i warunku.
Jeśli chcesz połączyć każdy wiersz z każdym, możesz użyć składni bez JOIN:
SELECT *
FROM students, courses;
Jeszcze jeden, trzeci przypadek - kiedy JOIN bez ON działa:
- Z
NATURAL JOIN— automatycznie dobiera kolumny o tych samych nazwach. - Z
USING— podajesz listę kolumn, po których łączysz tabele. CROSS JOIN— zawsze bez warunku - to samo co iloczyn kartezjański.
Błąd 2: Złe warunki łączenia
Czasem podajesz warunek łączenia, ale robisz to źle. Na przykład łączysz tabele nie po kluczach, tylko po niepowiązanych danych.
Załóżmy, że chcemy dostać listę studentów i kursów, na które są zapisani, ale mylimy się i łączymy tabele po niepowiązanych polach:
SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;
Takie zapytanie da zły wynik, bo student_id i course_id to zupełnie inne rzeczy.
Jak naprawić: upewnij się, że używasz właściwych kolumn do łączenia. Poprawne połączenie może wyglądać tak (jeśli masz tabelę enrollments, która łączy studentów z kursami):
SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Błąd 3: Duplikacja wierszy w wyniku
Kiedy dodajesz kilka JOIN do zapytania, czasem prowadzi to do duplikacji wierszy. Dzieje się tak, jeśli w tabelach JOIN są powtarzające się rekordy albo źle podałeś warunki łączenia.
Załóżmy, że student Otto jest dwa razy zapisany na ten sam kurs w tabeli enrollments.
Rekordy w enrollments:
| student_id | course_id |
|---|---|
| 1 | 101 |
| 1 | 101 |
Teraz zapytanie z JOIN da taki wynik:
SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Wynik:
| name | course_name |
|---|---|
| Otto | Matematyka |
| Otto | Matematyka |
Jak naprawić: po pierwsze, sprawdź, czy w twoich tabelach nie ma duplikatów. Po drugie, jeśli to oczekiwane zachowanie, usuwaj duplikaty za pomocą DISTINCT:
SELECT DISTINCT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Błąd 4: Utrata wierszy przy użyciu INNER JOIN
INNER JOIN zwraca tylko te wiersze, które mają dopasowanie w obu tabelach. Jeśli w jednej z tabel nie ma odpowiedniej wartości, wiersz zostanie pominięty. Możesz stracić dane, jeśli źle wybierzesz typ łączenia.
Załóżmy, że mamy studenta, który nie jest jeszcze zapisany na żaden kurs:
Studenci (students):
| student_id | name |
|---|---|
| 1 | Otto |
| 2 | Anna |
| 3 | Dhany |
Zapisy (enrollments):
| student_id | course_id |
|---|---|
| 1 | 101 |
| 2 | 102 |
Teraz zapytanie z INNER JOIN:
SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Wynik:
| name | course_name |
|---|---|
| Otto | Matematyka |
| Anna | Historia |
A gdzie Dhany? Jeśli chcesz uwzględnić studentów bez kursów, użyj LEFT JOIN:
SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id;
Błąd 5: Zła obsługa wartości NULL
Jeśli w jednej z tabel są wiersze z pustymi (NULL) wartościami, mogą nie pojawić się w wynikach (np. przy użyciu warunków filtrowania).
Przykład: używasz LEFT JOIN, ale potem dodajesz WHERE do filtrowania.
SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name = 'Matematyka';
Teraz studenci bez kursów nie pojawią się w wyniku, nawet jeśli użyłeś LEFT JOIN.
Jak naprawić: jeśli chcesz uwzględnić wiersze bez kursów, zamień WHERE na ON albo dodaj dodatkowy warunek:
SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name IS NULL OR courses.course_name = 'Matematyka';
Błąd 6: Mieszanie typów łączeń
Myli ci się, jakiego typu łączenia użyć. Na przykład stosujesz RIGHT JOIN, chociaż można by użyć LEFT JOIN, tylko zamieniając kolejność tabel.
Jak nie mieszać:
- Używaj
LEFT JOIN, jeśli możesz. To bardziej intuicyjne. - Zmień kolejność tabel, żeby nie musieć używać
RIGHT JOIN.
GO TO FULL VERSION