Subquery
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 5.Tóm tắt
Không thể viết WHERE price > AVG(price), vì hàm tổng hợp không dùng được
trong WHERE (bài GROUP BY và HAVING). Phải tính giá trung bình trước rồi mới
lọc; subquery làm việc này trong một câu.
Khái niệm
🪆 Subquery: câu SELECT đặt bên trong một câu SQL khác, kết quả của nó được dùng như một giá trị hoặc một danh sách.
Ví dụ
SELECT name, price
FROM products
WHERE price > (SELECT AVG(price) FROM products)
ORDER BY price;- Câu trong ngoặc chạy trước, trả về một con số: giá trung bình là 164800.
- Câu bên ngoài dùng con số đó để lọc, ra Balo và Máy tính.
- Subquery trả về một giá trị thì so sánh bằng
=,>,<. - Subquery trả về nhiều dòng thì dùng
IN.
Thử ngay
Khách nào có ít nhất một đơn đã thanh toán?
SELECT name
FROM customers
WHERE customer_id IN (
SELECT customer_id FROM orders WHERE status = 'PAID'
)
ORDER BY customer_id;Đoán trước khi chạy: An có một đơn PAID và một đơn NEW, Chi chỉ có
đơn CANCELLED. Ai nằm trong kết quả?
Xem kết quả
| NAME |
|---|
| An |
| Bình |
Subquery trả về danh sách mã khách có đơn PAID: 1 và 2. An có ít nhất một
đơn PAID nên được giữ. Chi không có đơn nào như vậy.
Lỗi hay gặp
So sánh bằng = với subquery trả về nhiều dòng. Oracle báo
ORA-01427: single-row subquery returns more than one row.
-- SAI — lỗi: có hai khách ở Hà Nội
SELECT order_id FROM orders
WHERE customer_id = (
SELECT customer_id FROM customers
WHERE city = 'Hà Nội'
);-- ĐÚNG — nhiều giá trị thì dùng IN
SELECT order_id FROM orders
WHERE customer_id IN (
SELECT customer_id FROM customers
WHERE city = 'Hà Nội'
);NOT IN với danh sách có NULL. Email của Chi là NULL. Chỉ cần danh sách
có một giá trị NULL là NOT IN không trả về dòng nào.
-- SAI — không trả về dòng nào
SELECT name FROM customers
WHERE email NOT IN (
SELECT email FROM customers WHERE city = 'Hà Nội'
);-- ĐÚNG — loại NULL khỏi danh sách
SELECT name FROM customers
WHERE email NOT IN (
SELECT email FROM customers
WHERE city = 'Hà Nội' AND email IS NOT NULL
);Tóm tắt
- Subquery là câu
SELECTlồng trong câu khác, chạy trước để lấy giá trị. - Trả về một giá trị thì dùng
=,>,<. Trả về nhiều dòng thì dùngIN. - Dùng subquery để lọc theo giá trị tổng hợp như trung bình.
- Cẩn thận
NOT INkhi danh sách có thể chứa NULL.
Tự kiểm tra
0/3 câuTìm đơn hàng của khách tên An. Câu nào đúng, biết có thể có nhiều khách trùng tên An?
Tìm sản phẩm có giá cao nhất. Câu nào đúng?
WHERE id NOT IN (1, 2, NULL) trả về bao nhiêu dòng?