JOIN trong SQL là gì?
Trong thực tế, cơ sở dữ liệu không chỉ có một bảng. Một hệ thống bán hàng có bảng customers (khách hàng), bảng orders (đơn hàng), bảng products (sản phẩm)... Để lấy thông tin có ý nghĩa, bạn cần kết hợp dữ liệu từ nhiều bảng lại — đó là lúc cần đến JOIN.
JOIN là câu lệnh SQL cho phép kết hợp các hàng từ hai hoặc nhiều bảng dựa trên một cột có liên quan giữa chúng — thường là khóa ngoại (foreign key) và khóa chính (primary key).
Trước hết, hãy tạo dữ liệu mẫu để dùng xuyên suốt bài viết:
-- Bảng khách hàng
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
-- Bảng đơn hàng
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT,
product VARCHAR(100),
amount DECIMAL(10,2)
);
-- Dữ liệu mẫu
INSERT INTO customers VALUES (1, 'Nguyễn Văn A', 'a@email.com');
INSERT INTO customers VALUES (2, 'Trần Thị B', 'b@email.com');
INSERT INTO customers VALUES (3, 'Lê Văn C', 'c@email.com'); -- Chưa có đơn hàng
INSERT INTO orders VALUES (1, 1, 'Laptop', 15000000);
INSERT INTO orders VALUES (2, 1, 'Chuột', 150000);
INSERT INTO orders VALUES (3, 2, 'Bàn phím', 500000);
Lưu ý: Lê Văn C (id=3) chưa có đơn hàng nào — điều này sẽ tạo sự khác biệt rõ ràng giữa các loại JOIN.
INNER JOIN — Lấy dữ liệu chung
INNER JOIN chỉ trả về các hàng có dữ liệu khớp ở cả hai bảng. Nếu một khách hàng không có đơn hàng, họ sẽ không xuất hiện trong kết quả.
SELECT customers.name, orders.product, orders.amount
FROM customers
INNER JOIN orders ON customers.id = orders.customer_id;
-- Kết quả:
-- name | product | amount
-- Nguyễn Văn A | Laptop | 15000000
-- Nguyễn Văn A | Chuột | 150000
-- Trần Thị B | Bàn phím | 500000
-- (Lê Văn C không xuất hiện vì không có đơn hàng)
INNER JOIN giống như phần giao nhau của hai tập hợp — chỉ lấy những gì tồn tại ở cả hai bên.
Khi nào dùng INNER JOIN: khi bạn chỉ muốn dữ liệu có liên kết đầy đủ ở cả hai bảng (ví dụ: chỉ lấy đơn hàng kèm tên khách hàng).
LEFT JOIN — Giữ toàn bộ bảng trái
LEFT JOIN trả về tất cả các hàng từ bảng bên trái, và dữ liệu khớp từ bảng bên phải. Nếu không có dữ liệu khớp bên phải, cột đó sẽ có giá trị NULL.
SELECT customers.name, orders.product, orders.amount
FROM customers
LEFT JOIN orders ON customers.id = orders.customer_id;
-- Kết quả:
-- name | product | amount
-- Nguyễn Văn A | Laptop | 15000000
-- Nguyễn Văn A | Chuột | 150000
-- Trần Thị B | Bàn phím | 500000
-- Lê Văn C | NULL | NULL ← xuất hiện, nhưng không có đơn hàng
Khi nào dùng LEFT JOIN: khi bạn muốn lấy tất cả dữ liệu từ bảng chính, kể cả những bản ghi chưa có dữ liệu liên quan. Ví dụ: "danh sách tất cả khách hàng, kể cả người chưa mua hàng".
RIGHT JOIN — Giữ toàn bộ bảng phải
RIGHT JOIN là đối xứng của LEFT JOIN — trả về tất cả hàng từ bảng bên phải, và dữ liệu khớp từ bảng bên trái.
SELECT customers.name, orders.product, orders.amount
FROM customers
RIGHT JOIN orders ON customers.id = orders.customer_id;
-- Kết quả: tất cả đơn hàng + tên khách hàng (NULL nếu không tìm thấy)
-- Trong ví dụ này kết quả giống INNER JOIN vì mọi order đều có customer
Lưu ý thực tế: hầu hết developer dùng LEFT JOIN thay vì RIGHT JOIN (bằng cách đổi vị trí bảng), vì LEFT JOIN dễ đọc hơn khi bảng chính luôn ở bên trái.
So sánh các loại JOIN
| Loại JOIN | Trả về gì | Khi nào dùng |
|---|---|---|
| INNER JOIN | Chỉ hàng khớp ở cả 2 bảng | Khi cần dữ liệu liên kết đầy đủ |
| LEFT JOIN | Tất cả bảng trái + khớp bảng phải | Khi bảng trái là "chính", bảng phải là "phụ" |
| RIGHT JOIN | Tất cả bảng phải + khớp bảng trái | Ít dùng, thay bằng LEFT JOIN đổi vị trí |
| FULL OUTER JOIN | Tất cả hàng cả 2 bảng | MySQL: dùng UNION thay thế |
Ví dụ thực tế — Database cửa hàng
Dùng alias (bí danh) để code ngắn gọn hơn, kết hợp WHERE và ORDER BY:
-- Dùng alias c và o để viết ngắn hơn
SELECT c.name AS ten_khach, o.product AS san_pham, o.amount AS gia_tien
FROM customers c
INNER JOIN orders o ON c.id = o.customer_id
WHERE o.amount > 200000
ORDER BY o.amount DESC;
-- Kết quả: chỉ đơn hàng > 200,000 VNĐ, sắp xếp từ cao xuống thấp
-- ten_khach | san_pham | gia_tien
-- Nguyễn Văn A | Laptop | 15000000
-- Trần Thị B | Bàn phím | 500000
-- Đếm số đơn hàng mỗi khách hàng
SELECT c.name, COUNT(o.id) AS so_don_hang, SUM(o.amount) AS tong_tien
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.id, c.name
ORDER BY tong_tien DESC;
-- Kết quả:
-- name | so_don_hang | tong_tien
-- Nguyễn Văn A | 2 | 15150000
-- Trần Thị B | 1 | 500000
-- Lê Văn C | 0 | NULL
Tổng kết
JOIN là một trong những kỹ năng SQL quan trọng nhất. Những điểm cần nhớ:
- INNER JOIN: chỉ lấy dữ liệu khớp ở cả 2 bảng
- LEFT JOIN: lấy tất cả bảng trái, dùng nhiều nhất trong thực tế
- Luôn dùng alias (c, o) để code dễ đọc hơn
- Có thể kết hợp JOIN với WHERE, ORDER BY, GROUP BY
Xem thêm: SQL là gì? | MySQL là gì? | Các câu lệnh SQL cơ bản