Trong quá trình làm việc với MySQL, lỗi [Err] 1242 - Subquery returns more than 1 row là một trong những thông báo phổ biến nhất khi thực hiện các truy vấn lồng nhau (subqueries). Lỗi này xảy ra khi một truy vấn con được kỳ vọng chỉ trả về một giá trị duy nhất (scalar value) để phục vụ một phép so sánh, nhưng thực tế nó lại trả về nhiều dòng dữ liệu.
Nguyên nhân gây lỗi
Thông thường, lỗi này xuất hiện khi bạn sử dụng các toán tử so sánh đơn lẻ như =, >, <, >=, <= hoặc != trước một truy vấn con. Nếu truy vấn con đó tìm thấy nhiều hơn một bản ghi khớp với điều kiện, hệ thống sẽ không biết phải lấy giá trị nào để so sánh và dẫn đến xung đột.
Ví dụ về một câu lệnh gây lỗi:
SELECT ten_sinh_vien
FROM danh_sach_lop
WHERE id_sinh_vien = (
SELECT id_nguoi_dung
FROM dang_ky_khoa_hoc
WHERE ma_mon_hoc = 'CS101'
);
Nếu môn học 'CS101' có từ 2 sinh viên đăng ký trở lên, câu lệnh trên sẽ vấp phải lỗi 1242 ngay lập tức.
Các giải pháp xử lý hiệu quả
1. Sử dụng từ khóa IN
Đây là cách phổ biến nhất để thay thế toán tử =. Từ khóa IN cho phép so sánh một giá trị với một tập hợp các giá trị trả về từ truy vấn con.
-- Thay đổi dấu '=' thành 'IN'
SELECT ten_sinh_vien
FROM danh_sach_lop
WHERE id_sinh_vien IN (
SELECT id_nguoi_dung
FROM dang_ky_khoa_hoc
WHERE ma_mon_hoc = 'CS101'
);
2. Sử dụng ANY hoặc SOME
Từ khóa ANY (hoặc đồng nghĩa là SOME) được dùng kết hợp với các toán tử so sánh. Điều kiện sẽ đúng nếu phép so sánh khớp với bất kỳ giá trị nào trong tập kết quả của truy vấn con.
SELECT ten_san_pham
FROM kho_hang
WHERE gia_ban > ANY (
SELECT gia_niem_yet
FROM bang_gia_chi_tiet
WHERE danh_muc = 'DienTu'
);
3. Sử dụng từ khóa ALL
Ngược lại với ANY, từ khóa ALL yêu cầu điều kiện phải đúng với tất cả các giá trị trả về từ truy vấn con.
SELECT ma_nhan_vien
FROM luong_thang
WHERE muc_luong > ALL (
SELECT muc_luong_co_ban
FROM quy_dinh_luong
WHERE khu_vuc = 'Vung1'
);
4. Giới hạn kết quả trả về bằng LIMIT
Nếu logic nghiệp vụ chỉ yêu cầu lấy một giá trị duy nhất (ví dụ: giá trị mới nhất hoặc cao nhất), bạn có thể thêm LIMIT 1 vào cuối truy vấn con để đảm bảo nó luôn trả về một dòng.
UPDATE ho_so_nhan_su
SET phong_ban_moi = (
SELECT id_phong_ban
FROM lich_su_cong_tac
WHERE id_nv = 105
ORDER BY ngay_dieu_dong DESC
LIMIT 1
)
WHERE id_nv = 105;
5. Kiểm tra tính toàn vẹn của dữ liệu
Đôi khi lỗi này phát sinh do dữ liệu bị trùng lặp không mong muốn. Trong trường hợp này, bạn cần rà soát lại các ràng buộc (constraints) hoặc logic ghi dữ liệu để đảm bảo tính duy nhất. Việc sử dụng từ khóa DISTINCT trong truy vấn con cũng có thể giúp loại bỏ các giá trị trùng lặp nếu chúng có cùng giá trị.
CASE
WHEN ma_hoc_phan IN (
SELECT DISTINCT ten_mon
FROM bang_diem
WHERE mssv = '20230001'
)
THEN 'Da_Hoc'
ELSE 'Chua_Hoc'
END;
Tổng kết toán tử
- IN: Tương đương với
= ANY. - ANY/SOME: So sánh với bất kỳ giá trị nào trong danh sách.
- ALL: So sánh với tất cả các giá trị trong danh sách.