top of page

JOIN Trong SQL Là Gì?

  • 3 ngày trước
  • 10 phút đọc

Bạn đang học SQL và gặp câu hỏi: "Tại sao phải JOIN? Viết WHERE hai bảng không được sao?" Hoặc bạn đã biết JOIN nhưng cứ nhầm lẫn giữa LEFT JOIN và INNER JOIN, lấy ra kết quả sai mà không biết tại sao?


Bài viết này giải thích JOIN trong SQL theo cách trực quan nhất, dùng ví dụ từ bảng dữ liệu bán hàng quen thuộc, có hình minh họa kèm theo để bạn không chỉ hiểu mà còn nhớ lâu và áp dụng đúng ngay lần đầu.


JOIN Trong SQL Là Gì?

JOIN trong SQL là câu lệnh dùng để kết hợp dữ liệu từ hai hay nhiều bảng lại thành một kết quả duy nhất, dựa trên một cột mà cả hai bảng đều có chung.


các loại JOINS trong SQL

Hình dung thế này: Bạn có hai danh sách riêng: một danh sách tên khách hàng, một danh sách đơn hàng. Mỗi đơn hàng có mã khách hàng. JOIN chính là cách để bạn ghép tên khách hàng vào bên cạnh đơn hàng tương ứng trong một lệnh SQL duy nhất.


sql

SELECT kh.tên_khách_hàng, dh.ngày_đặt, dh.tổng_tiền
FROM khách_hàng kh
JOIN đơn_hàng dh ON kh.id = dh.id_khách_hàng;

Đọc câu lệnh trên như tiếng Anh bình thường: "Lấy tên khách hàng, ngày đặt và tổng tiền – từ bảng khách hàng ghép với bảng đơn hàng tại điều kiện: id khách hàng ở hai bảng phải bằng nhau."


Một điều ít người biết: JOIN không phải là một câu lệnh duy nhất mà là một họ các câu lệnh, mỗi loại cho kết quả khác nhau. Đây chính là lý do nhiều người nhầm lẫn khi mới học.


Tại Sao Cần JOIN? Dùng WHERE Không Đủ Sao?

Câu hỏi hay. Thực tế bạn có thể dùng WHERE để kết hợp hai bảng theo kiểu cũ:


sql

-- Cách cũ (không dùng JOIN)
SELECT kh.tên, dh.tổng_tiền
FROM khách_hàng kh, đơn_hàng dh
WHERE kh.id = dh.id_khách_hàng;

Nhưng cách này có 2 vấn đề lớn:


Thứ nhất, chỉ trả về dòng có ở CẢ HAI bảng. Nếu có khách hàng chưa đặt đơn nào, họ sẽ biến mất khỏi kết quả. Đây là thứ mà LEFT JOIN giải quyết được còn WHERE thì không.


Thứ hai, dễ quên điều kiện WHERE, sinh ra "bảng tích" khổng lồ. Nếu quên WHERE, SQL sẽ ghép tất cả mọi dòng với mọi dòng: 1.000 khách hàng × 10.000 đơn hàng = 10.000.000 dòng kết quả. Máy tính treo ngay lập tức.


JOIN ra đời để giải quyết chính xác những vấn đề này rõ ràng hơn, an toàn hơn và mạnh hơn.


Hai Khái Niệm Cần Hiểu Trước Khi Học JOIN


Khóa Chính (Primary Key)

Mỗi bảng thường có một cột định danh duy nhất cho từng dòng, gọi là khóa chính. Ví dụ: cột id trong bảng Khách hàng. Không có hai khách hàng nào có cùng id.


Khóa Ngoại (Foreign Key)

Khi bảng A muốn tham chiếu đến bảng B, bảng A sẽ lưu thêm một cột chứa giá trị id của bảng B gọi là khóa ngoại. Ví dụ: bảng Đơn hàng có cột id_khách_hàng để biết đơn này của ai.

JOIN hoạt động bằng cách khớp khóa ngoại ở bảng này với khóa chính ở bảng kia.


Xuyên suốt bài, chúng ta sẽ dùng hai bảng ví dụ sau – đơn giản, thực tế và dễ hình dung:


Bảng Khách_hàng:

id

tên

thành_phố

1

An

HCM

2

Bình

HN

3

Chi

HCM

4

Dũng

ĐN

Bảng Đơn_hàng:

id_đơn

id_khách

tổng_tiền

101

1

500.000

102

2

800.000

103

1

300.000

104

5

200.000


Lưu ý: Khách hàng Dũng (id=4) chưa đặt đơn nào. Đơn 104 có id_khách=5 nhưng không có khách hàng nào có id=5. Đây là hai tình huống mà mỗi loại JOIN xử lý khác nhau, hãy theo dõi kỹ!


INNER JOIN: Lấy Phần Chung Của Hai Bảng

INNER JOIN chỉ trả về những dòng có khớp ở CẢ HAI bảng. Nếu một bên không có, dòng đó bị bỏ qua hoàn toàn.


Hình dung: Đây là phần giao nhau của hai vòng tròn Venn.


Cú Pháp

sql

SELECT kh.tên, dh.tổng_tiền
FROM khách_hàng kh
INNER JOIN đơn_hàng dh ON kh.id = dh.id_khách
ORDER BY kh.tên;

Kết Quả

tên

tổng_tiền

An

500.000

An

300.000

Bình

800.000


Giải thích: Chỉ An và Bình có đơn hàng khớp → chỉ họ xuất hiện. Dũng (không có đơn) và đơn 104 (không có khách) đều bị loại.


Khi Nào Dùng INNER JOIN?

Dùng khi bạn chỉ muốn lấy dữ liệu có đầy đủ thông tin ở cả hai bảng. Ví dụ: lấy danh sách đơn hàng kèm tên khách hàng, chỉ lấy đơn có khách hàng hợp lệ.


Lưu ý: Viết JOIN không có từ khóa INNER phía trước vẫn hoạt động, SQL mặc định hiểu là INNER JOIN. Đây là dạng ngắn gọn được dùng phổ biến nhất.


LEFT JOIN: Giữ Nguyên Bảng Trái, Ghép Thêm Bảng Phải

LEFT JOIN trả về tất cả dòng của bảng bên trái (bảng viết trước FROM), dù có khớp với bảng phải hay không. Nếu không khớp, cột từ bảng phải sẽ hiển thị NULL.


Hình dung: Lấy toàn bộ vòng tròn bên trái + phần giao nhau.


Cú Pháp

sql

SELECT kh.tên, dh.tổng_tiền
FROM khách_hàng kh
LEFT JOIN đơn_hàng dh ON kh.id = dh.id_khách;

Kết Quả

tên

tổng_tiền

An

500.000

An

300.000

Bình

800.000

Chi

NULL

Dũng

NULL

Giải thích: Tất cả 4 khách hàng đều xuất hiện. Chi và Dũng chưa có đơn nên cột tổng_tiền hiển thị NULL. Đơn 104 (không có khách hàng khớp) không xuất hiện vì đó là bảng phải.


Khi Nào Dùng LEFT JOIN?

Đây là loại JOIN phổ biến nhất trong thực tế. Dùng khi bạn muốn lấy toàn bộ dữ liệu từ bảng chính (bảng trái) và ghép thêm thông tin từ bảng phụ nếu có.


Ví dụ thực tế:

  • Danh sách tất cả sản phẩm, kể cả những sản phẩm chưa bán được lần nào

  • Danh sách tất cả nhân viên, kể cả người chưa hoàn thành dự án nào

  • Tất cả khách hàng kèm số đơn hàng, khách chưa mua thì hiện số 0

Mẹo hay: Để tìm khách hàng chưa bao giờ đặt đơn, dùng LEFT JOIN + lọc WHERE NULL:

sql

SELECT kh.tên
FROM khách_hàng kh
LEFT JOIN đơn_hàng dh ON kh.id = dh.id_khách
WHERE dh.id_đơn IS NULL;
-- Kết quả: Chi, Dũng

RIGHT JOIN: Ngược Lại Của LEFT JOIN

RIGHT JOIN giữ nguyên toàn bộ bảng bên phải, ghép thêm bảng trái nếu có khớp. Dòng không khớp từ bảng trái hiển thị NULL.


Cú Pháp

sql

SELECT kh.tên, dh.id_đơn, dh.tổng_tiền
FROM khách_hàng kh
RIGHT JOIN đơn_hàng dh ON kh.id = dh.id_khách;

Kết Quả

tên

id_đơn

tổng_tiền

An

101

500.000

Bình

102

800.000

An

103

300.000

NULL

104

200.000

Giải thích: Tất cả 4 đơn hàng đều xuất hiện. Đơn 104 không có khách hàng khớp → hiển thị NULL. Dũng và Chi biến mất vì không có đơn hàng nào.


Khi Nào Dùng RIGHT JOIN?

Trên thực tế, RIGHT JOIN ít được dùng vì bạn hoàn toàn có thể đổi thứ tự bảng rồi dùng LEFT JOIN để đạt kết quả tương tự. Nhiều Data Analyst thực tế chỉ dùng LEFT JOIN và INNER JOIN là đủ cho 95% công việc.


FULL JOIN: Lấy Tất Cả Dù Có Khớp Hay Không

FULL JOIN (hay FULL OUTER JOIN) trả về tất cả dòng của cả hai bảng. Phần không khớp ở bên nào sẽ hiển thị NULL cho phần còn lại.


Hình dung: Lấy toàn bộ hai vòng tròn Venn, kể cả phần không giao nhau.


Cú Pháp

sql

SELECT kh.tên, dh.id_đơn, dh.tổng_tiền
FROM khách_hàng kh
FULL JOIN đơn_hàng dh ON kh.id = dh.id_khách;

Kết Quả

tên

id_đơn

tổng_tiền

An

101

500.000

Bình

102

800.000

An

103

300.000

Chi

NULL

NULL

Dũng

NULL

NULL

NULL

104

200.000

Giải thích: Không ai bị bỏ sót, cả khách hàng chưa đặt đơn lẫn đơn hàng không có khách đều xuất hiện đủ.


Khi Nào Dùng FULL JOIN?

Dùng khi bạn cần kiểm tra tính toàn vẹn dữ liệu để phát hiện dữ liệu mồ côi, dữ liệu thiếu liên kết. Ví dụ: kiểm tra xem có đơn hàng nào không có khách hàng hợp lệ không, hoặc có khách hàng nào bị thiếu thông tin đơn hàng.


Lưu ý: MySQL không hỗ trợ FULL OUTER JOIN trực tiếp. Cần dùng kết hợp LEFT JOIN + UNION + RIGHT JOIN. PostgreSQL và SQL Server hỗ trợ đầy đủ.


CROSS JOIN: Kết Hợp Mọi Dòng Với Mọi Dòng

CROSS JOIN ghép mỗi dòng của bảng trái với tất cả dòng của bảng phải, không cần điều kiện khớp. Kết quả là tích của hai bảng.


sql

SELECT mau, size
FROM màu_sắc
CROSS JOIN kích_cỡ;

Nếu bảng màu có 4 màu, bảng kích cỡ có 3 size → kết quả sẽ có 4 × 3 = 12 dòng (tất cả tổ hợp màu & size có thể có).


Khi Nào Dùng CROSS JOIN?

Dùng khi cần tạo ra tất cả tổ hợp có thể giữa hai tập hợp. Ví dụ: tạo bảng giá tất cả combo sản phẩm, hoặc lịch thi đấu vòng tròn.


Cẩn thận: CROSS JOIN rất ít được dùng vì kết quả có thể cực kỳ lớn. Hai bảng 1.000 dòng × 1.000 dòng = 1.000.000 dòng kết quả. Chỉ dùng khi thực sự cần thiết.


SELF JOIN: Một Bảng Nối Với Chính Nó

SELF JOIN không phải là một loại JOIN mới – đây là kỹ thuật dùng INNER JOIN hoặc LEFT JOIN nhưng cả hai bảng đều là cùng một bảng, chỉ khác tên gọi (alias).


Dùng khi trong một bảng có mối quan hệ giữa các dòng với nhau. Ví dụ điển hình: bảng nhân viên có cột id_quản_lý tham chiếu về chính cột id trong cùng bảng đó.


sql

-- Lấy tên nhân viên và tên quản lý trực tiếp của họ
SELECT nv.tên AS nhân_viên, ql.tên AS quản_lý
FROM nhân_viên nv
LEFT JOIN nhân_viên ql ON nv.id_quản_lý = ql.id;

nhân_viên

quản_lý

An

Giám đốc

Bình

An

Chi

An

Dũng

NULL

Dũng là sếp cao nhất nên không có quản lý → hiển thị NULL.


Nên Dùng Loại JOIN Nào?

Loại JOIN

Trả về gì?

Dùng khi nào?

INNER JOIN

Chỉ dòng khớp ở cả hai bảng

Muốn dữ liệu đầy đủ ở cả hai phía

LEFT JOIN

Tất cả bảng trái + phần khớp bảng phải

Bảng trái là chính, bảng phải là phụ thêm

RIGHT JOIN

Tất cả bảng phải + phần khớp bảng trái

Như LEFT JOIN nhưng đổi thứ tự ưu tiên

FULL JOIN

Tất cả dòng của cả hai bảng

Kiểm tra tính toàn vẹn, tìm dữ liệu mồ côi

CROSS JOIN

Mọi tổ hợp dòng giữa hai bảng

Tạo danh sách tổ hợp có thể

SELF JOIN

Bảng tự nối với chính nó

Dữ liệu có quan hệ phân cấp trong cùng bảng

Nguyên tắc chọn JOIN nhanh:

  • Chỉ cần dữ liệu khớp cả hai? → INNER JOIN

  • Cần giữ lại hết bảng A dù B có hay không? → LEFT JOIN

  • Cần xem dữ liệu nào bị thiếu ở cả hai phía? → FULL JOIN

  • 90% công việc hàng ngày chỉ cần: INNER JOIN + LEFT JOIN


Các Lỗi Thường Gặp Khi Dùng JOIN

Lỗi 1: Quên điều kiện ON, gây ra CROSS JOIN ngoài ý muốn

sql

-- SAI: Thiếu ON → Kết quả là tích Descartes khổng lồ!
SELECT * FROM khách_hàng JOIN đơn_hàng;

-- ĐÚNG
SELECT * FROM khách_hàng kh
JOIN đơn_hàng dh ON kh.id = dh.id_khách;

Lỗi 2: Tên cột trùng ở hai bảng, không chỉ định rõ

sql

-- SAI: Ambiguous column 'id'
SELECT id, tên FROM khách_hàng kh JOIN đơn_hàng dh ON kh.id = dh.id_khách;

-- ĐÚNG: Chỉ định rõ bảng nào
SELECT kh.id, kh.tên, dh.tổng_tiền
FROM khách_hàng kh JOIN đơn_hàng dh ON kh.id = dh.id_khách;

Lỗi 3: Nhầm LEFT JOIN và INNER JOIN dẫn đến mất dữ liệu

Đây là lỗi phổ biến nhất. Bạn muốn tất cả sản phẩm kể cả chưa bán, nhưng lại dùng INNER JOIN → những sản phẩm chưa bán biến mất khỏi kết quả mà không báo lỗi.


sql

-- SAI khi muốn tất cả sản phẩm
SELECT sp.tên, COUNT(ct.id_sản_phẩm) AS lần_bán
FROM sản_phẩm sp
INNER JOIN chi_tiết_đơn ct ON sp.id = ct.id_sản_phẩm  -- Sản phẩm chưa bán sẽ biến mất!
GROUP BY sp.tên;

-- ĐÚNG
SELECT sp.tên, COUNT(ct.id_sản_phẩm) AS lần_bán
FROM sản_phẩm sp
LEFT JOIN chi_tiết_đơn ct ON sp.id = ct.id_sản_phẩm
GROUP BY sp.tên;

Lỗi 4: JOIN nhiều bảng sai thứ tự

Khi JOIN 3 bảng trở lên, thứ tự JOIN ảnh hưởng đến kết quả khi dùng LEFT JOIN. Hãy luôn JOIN theo thứ tự logic từ bảng chính ra bảng phụ.


sql

-- Thứ tự logic: Khách hàng → Đơn hàng → Chi tiết đơn
SELECT kh.tên, dh.ngày_đặt, sp.tên_sản_phẩm
FROM khách_hàng kh
LEFT JOIN đơn_hàng dh ON kh.id = dh.id_khách
LEFT JOIN chi_tiết_đơn ct ON dh.id_đơn = ct.id_đơn
LEFT JOIN sản_phẩm sp ON ct.id_sản_phẩm = sp.id;

JOIN Trong Thực Tế: Data Analyst Dùng Như Thế Nào?

Để hiểu tầm quan trọng của JOIN, hãy xem một bài toán thực tế:


Bài toán: Tìm top 5 thành phố có doanh thu cao nhất trong tháng 6/2026, kèm số đơn hàng và trung bình giá trị đơn.


sql

SELECT 
    kh.thành_phố,
    COUNT(dh.id_đơn)    AS số_đơn,
    SUM(dh.tổng_tiền)   AS tổng_doanh_thu,
    AVG(dh.tổng_tiền)   AS tb_giá_trị_đơn
FROM khách_hàng kh
INNER JOIN đơn_hàng dh ON kh.id = dh.id_khách
WHERE dh.ngày_đặt BETWEEN '2026-06-01' AND '2026-06-30'
GROUP BY kh.thành_phố
ORDER BY tổng_doanh_thu DESC
LIMIT 5;

Câu SQL này kết hợp: INNER JOIN (ghép khách hàng và đơn hàng) + WHERE (lọc tháng 6) + GROUP BY (nhóm theo thành phố) + ORDER BY + LIMIT (lấy top 5). Đây là dạng query Data Analyst viết hàng ngày.


Xem thêm:

JOIN trong SQL là gì? Đó là cách để bạn kéo thông tin từ nhiều bảng dữ liệu về cùng một chỗ, thứ mà VLOOKUP trong Excel làm rất vất vả nhưng SQL JOIN làm trong vài dòng lệnh.

Tóm lại những điểm cốt lõi cần nhớ:

  • INNER JOIN: chỉ lấy phần khớp ở cả hai bảng, dùng nhiều nhất

  • LEFT JOIN: giữ toàn bộ bảng trái, ghép bảng phải nếu có, dùng nhiều thứ hai

  • FULL JOIN: lấy hết cả hai bảng, dùng để kiểm tra dữ liệu

  • RIGHT JOIN / CROSS JOIN / SELF JOIN: dùng trong trường hợp đặc biệt

  • 90% công việc thực tế của Data Analyst chỉ cần INNER JOIN + LEFT JOIN


Hãy thực hành ngay với dataset mẫu trên tại đây, không cần cài đặt, chạy thẳng trên trình duyệt. Tạo hai bảng nhỏ, thử lần lượt từng loại JOIN và so sánh kết quả, đó là cách nhanh nhất để nhớ lâu. Biết JOIN là nền tảng quan trọng. Nhưng để trở thành Data Analyst được doanh nghiệp săn đón năm 2026, bạn cần kết hợp SQL với Power BI, Python và tư duy phân tích kinh doanh, tất cả trong một lộ trình thực chiến. Xem chi tiết chương trình tại đây


Truy cập ngay Mastering Data Analytics để đọc thêm nhiều bài viết thú vị về SQL và phân tích dữ liệu!


"Mastering Data Analytics - TIÊN PHONG mở ra chương trình Agentic AI Analytics LẦN ĐẦU TIÊN tại Việt Nam"

Với mọi thắc mắc bạn có thể liên hệ Zalo 0961 48 66 48 để được tư vấn miễn phí. Hoặc bạn có thể inbox fanpage Mastering Data Analytics tham khảo lịch khai giảng sớm nhất!


Bình luận


bottom of page