CodeGym /Các khóa học /SQL SELF /Lọc dữ liệu với INNOT IN

Lọc dữ liệu với INNOT IN

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

Giả sử bạn đang làm việc với database của trường đại học và cần tìm sinh viên học ở các khóa cụ thể. Ví dụ, "Lập trình", "Toán học" và "Vật lý". Tất nhiên, bạn có thể viết một truy vấn dài với nhiều điều kiện kiểu như:

SELECT *
FROM students 
WHERE course = 'Lập trình'
   OR course = 'Toán học'
   OR course = 'Vật lý';

Nhưng mà nói thật nhé, viết kiểu này vừa mệt vừa xấu. May mà có toán tử IN, giúp viết truy vấn gọn hơn và tiết kiệm thời gian:

SELECT *
FROM students 
WHERE course IN ('Lập trình', 'Toán học', 'Vật lý');

Nghe như phép thuật nhỉ? Thay vì nhiều điều kiện OR, mình chỉ cần bảo SQL tìm giá trị trong danh sách này thôi. Nếu muốn kiểm tra giá trị không nằm trong danh sách, dùng NOT INTìm tất cả những gì không có trong danh sách này.

Cú pháp của toán tử IN

Đây là cú pháp chung của toán tử IN:

SELECT cột
FROM bảng
WHERE cột IN (giá_trị1, giá_trị2, giá_trị3, ...);

Giờ cùng xem vài ví dụ nhé.

Ví dụ 1: Sinh viên học nhiều khóa

Giả sử bạn có bảng students:

id name course
1 Anna Lập trình
2 Mello Vật lý
3 Kate Toán học
4 Dan Hóa học
5 Olly Sinh học

Mình muốn tìm tất cả sinh viên học "Lập trình", "Toán học" hoặc "Vật lý". Dùng IN thôi:

SELECT name, course
FROM students
WHERE course IN ('Lập trình', 'Toán học', 'Vật lý');

Kết quả:

name course
Anna Lập trình
Mello Vật lý
Kate Toán học

Nhìn xem, toán tử IN làm mọi thứ đơn giản hơn hẳn. Không cần viết dài dòng với OR, chỉ cần liệt kê danh sách giá trị bạn quan tâm.

Ví dụ 2: Sinh viên không học các khóa nhất định

Giờ giả sử bạn muốn tìm sinh viên không học "Lập trình", "Toán học" và "Vật lý". Dùng NOT IN nhé:

SELECT name, course
FROM students
WHERE course NOT IN ('Lập trình', 'Toán học', 'Vật lý');

Kết quả:

name course
Dan Hóa học
Olly Sinh học

Vậy là, toán tử NOT IN trả về tất cả các dòng mà giá trị cột course không nằm trong danh sách đã cho.

Dùng INNOT IN với subquery

Các toán tử INNOT IN cực kỳ hữu ích khi cần so sánh dữ liệu giữa hai bảng. Ví dụ, giả sử bạn có hai bảng:

Bảng students:

id name course_id
1 Anna 101
2 Mello 102
3 Kate 103
4 Dan 104

Bảng courses:

id name
101 Lập trình
102 Vật lý
103 Toán học
105 Hóa học

Giả sử bạn cần tìm sinh viên đã đăng ký các khóa có trong bảng courses. Lúc này subquery với IN sẽ giúp bạn:

SELECT name
FROM students
WHERE course_id IN (
    SELECT id
    FROM courses
);

Truy vấn này hoạt động như sau: subquery SELECT id FROM courses trả về danh sách tất cả id khóa học. Sau đó toán tử IN kiểm tra xem course_id có nằm trong danh sách đó không.

Kết quả:

name
Anna
Mello
Kate

Tại sao Dan bị bỏ qua? Vì course_id của Dan (104) không có trong bảng courses.

Đặc điểm khi làm việc với NULL

Toán tử IN có một điểm cần chú ý: nếu trong danh sách giá trị có NULL, nó có thể ảnh hưởng đến kết quả truy vấn. Xem ví dụ nhé.

Bảng grades:

student_id course_id grade
1 101 A
2 102 NULL
3 103 B

Truy vấn tìm sinh viên có điểm trong ('A', 'B', 'C') có thể như sau:

SELECT student_id
FROM grades
WHERE grade IN ('A', 'B', 'C');

Kết quả:

student_id
1
3

Dòng có NULL ở cột grade bị bỏ qua, vì NULL không được coi là một phần của bất kỳ danh sách nào.

Giờ thử dùng toán tử NOT IN nhé. Ví dụ:

SELECT student_id
FROM grades
WHERE grade NOT IN ('A', 'B', 'C');

Bạn mong sẽ thấy dòng với student_id = 2, nhưng kết quả lại rỗng! Tại sao? Vì NULL khi so sánh với bất kỳ giá trị nào trong danh sách đều trả về UNKNOWN. Điều này dễ gây nhầm lẫn, nên khi dùng NOT IN hãy chú ý nếu có cột chứa NULL. Cách tốt nhất là kiểm tra NULL rõ ràng:

SELECT student_id
FROM grades
WHERE grade NOT IN ('A', 'B', 'C')
   OR grade IS NULL;

Kết quả:

student_id
2

Khuyến nghị khi dùng INNOT IN

Dùng IN để code SQL dễ đọc hơn
Nếu bạn cần kiểm tra một cột có nằm trong danh sách giá trị nào đó không, luôn ưu tiên dùng IN thay vì nhiều điều kiện OR.

Cẩn thận với NOT INNULL
Nếu dữ liệu có cột chứa NULL, nó có thể gây ra kết quả bất ngờ. Tốt nhất là xử lý NULL rõ ràng khi dùng NOT IN.

Dùng index để tăng tốc subquery
Nếu IN dùng với subquery, hãy đảm bảo cột trong subquery đã được index để tránh vấn đề hiệu năng.

Ví dụ thực tế

Giả sử bạn làm việc với hệ thống shop online. Bạn có bảng ordersusers. Bạn muốn tìm tất cả user chưa từng đặt hàng.

Bảng users:

id name
1 Anna
2 Mello
3 Kate
4 Dan

Bảng orders:

id user_id total
1 1 500
2 3 300

Dùng NOT IN để giải quyết nhé:

SELECT name
FROM users
WHERE id NOT IN (
    SELECT user_id
    FROM orders
);

Kết quả:

name
Mello
Dan

Truy vấn này hoạt động như sau: subquery SELECT user_id FROM orders trả về id của tất cả user đã đặt hàng (1 và 3). Sau đó toán tử NOT IN loại bỏ họ, chỉ giữ lại những ai chưa từng đặt hàng (Mello và Dan).

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION