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 IN — Tì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 IN và NOT IN với subquery
Các toán tử IN và NOT 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 IN và NOT 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 IN và NULL
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 orders và users. 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).
GO TO FULL VERSION