CodeGym /Các khóa học /SQL SELF /Những lỗi thường gặp khi dùng JOIN

Những lỗi thường gặp khi dùng JOIN

SQL SELF
Mức độ , Bài học
Có sẵn

Bây giờ là lúc nói về cuộc sống. Về mặt mà ai cũng phải gặp: lỗi. Bắt lỗi, sửa lỗi và hiểu lỗi – đó là phần không thể thiếu khi làm việc với dữ liệu. Cùng xem thử những cái bẫy nào hay gặp khi dùng JOIN trong SQL, và làm sao để né chúng nhé.

Lỗi 1: Bỏ qua điều kiện nối – tạo ra phép nhân Descartes

Lỗi phổ biến nhất – quên chỉ định điều kiện nối khi dùng ON. Khi đó sẽ xảy ra phép nhân Descartes, tức là mỗi dòng của bảng đầu sẽ kết hợp với mỗi dòng của bảng thứ hai. Kết quả là bạn nhận được một đống dòng vô nghĩa, chỉ làm bạn rối thêm thôi.

Lấy ví dụ nhé. Giả sử mình có các bảng sau:

Sinh viên (students):

student_id name
1 Otto
2 Anna

Khoá học (courses):

course_id course_name
101 Toán học
102 Lịch sử

Giờ mình viết truy vấn mà quên mất ON:

SELECT *
FROM students
JOIN courses;

Kết quả:

student_id name course_id course_name
1 Otto 101 Toán học
1 Otto 102 Lịch sử
2 Anna 101 Toán học
2 Anna 102 Lịch sử

Nhìn không đúng chút nào nhỉ? Cơn ác mộng này gọi là phép nhân Descartes.

Cách sửa: dùng ON để chỉ rõ dữ liệu liên kết giữa các bảng như thế nào.

SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;

Và đây lại mở ra một chương mới của lỗi...

Bảo vệ khỏi "gà mờ"

Vấn đề này phổ biến đến mức PostgreSQL đã cấm dùng JOIN mà không có ON và điều kiện.

Nếu bạn thực sự muốn kết hợp mọi dòng với mọi dòng, có thể dùng cú pháp không cần JOIN:

SELECT *
FROM students, courses;

Thêm một trường hợp nữa – khi JOIN không có ON vẫn chạy được:

  • Với NATURAL JOIN – tự động ghép các cột trùng tên.
  • Với USING – bạn chỉ định danh sách cột để ghép.
  • CROSS JOIN – luôn không có điều kiện – cũng là phép nhân Descartes.

Lỗi 2: Điều kiện nối sai

Đôi khi bạn có điều kiện nối, nhưng lại sai. Ví dụ, nối bảng không phải bằng khoá mà bằng dữ liệu không liên quan.

Giả sử bạn muốn lấy danh sách sinh viên và khoá học mà họ đăng ký, nhưng lại nối bảng bằng các trường không liên quan:

SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;

Truy vấn này sẽ cho ra kết quả sai, vì student_idcourse_id là hai thứ hoàn toàn khác nhau.

Cách sửa: hãy chắc chắn bạn dùng đúng cột để nối. Nối đúng có thể như sau (nếu bạn có bảng enrollments liên kết sinh viên với khoá học):

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;

Lỗi 3: Trùng lặp dòng trong kết quả

Khi bạn thêm nhiều JOIN vào truy vấn, đôi khi sẽ bị trùng lặp dòng. Điều này xảy ra nếu trong các bảng JOIN có dữ liệu lặp lại, hoặc bạn chỉ định điều kiện nối sai.

Ví dụ, sinh viên Otto đăng ký hai lần cùng một khoá học trong bảng enrollments.

Dữ liệu trong enrollments:

student_id course_id
1 101
1 101

Giờ truy vấn với JOIN sẽ ra kết quả như sau:

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;

Kết quả:

name course_name
Otto Toán học
Otto Toán học

Cách sửa: đầu tiên, hãy chắc chắn bảng của bạn không có dữ liệu trùng lặp. Thứ hai, nếu đây là hành vi mong muốn, hãy loại bỏ dòng trùng bằng 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;

Lỗi 4: Mất dòng khi dùng INNER JOIN

INNER JOIN chỉ trả về những dòng khớp ở cả hai bảng. Nếu một bảng không có giá trị tương ứng, dòng đó sẽ bị loại bỏ. Bạn có thể mất dữ liệu nếu chọn sai loại nối.

Giả sử mình có một sinh viên chưa đăng ký khoá học nào:

Sinh viên (students):

student_id name
1 Otto
2 Anna
3 Dhany

Đăng ký (enrollments):

student_id course_id
1 101
2 102

Giờ truy vấn với 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;

Kết quả:

name course_name
Otto Toán học
Anna Lịch sử

Thế còn Dhany đâu? Nếu bạn muốn cả sinh viên chưa có khoá học cũng xuất hiện, hãy dùng 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;

Lỗi 5: Xử lý sai giá trị NULL

Nếu một trong các bảng có dòng với giá trị rỗng (NULL), chúng có thể bị loại khỏi kết quả (ví dụ khi dùng điều kiện lọc).

Ví dụ: bạn dùng LEFT JOIN nhưng lại thêm WHERE để lọc.

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 = 'Toán học';

Bây giờ sinh viên không có khoá học sẽ không xuất hiện trong kết quả, dù bạn đã dùng LEFT JOIN.

Cách sửa: nếu muốn bao gồm cả dòng không có khoá học, hãy thay WHERE bằng ON hoặc thêm điều kiện nữa:

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 = 'Toán học';

Lỗi 6: Nhầm lẫn giữa các loại nối

Bạn bị rối không biết dùng loại nối nào. Ví dụ, dùng RIGHT JOIN trong khi chỉ cần LEFT JOIN và đảo thứ tự bảng là được.

Cách tránh nhầm lẫn:

  • Dùng LEFT JOIN nếu có thể. Nó dễ hiểu hơn nhiều.
  • Đổi thứ tự bảng để khỏi phải dùng RIGHT JOIN.
1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Nhiều JOIN
Nhiều JOIN
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION