SELF JOIN là cách để kết nối một bảng với chính nó. Nghe thì hơi lạ đúng không: tại sao lại phải kết nối bảng với chính nó nhỉ? Nhưng thực tế thì kiểu bài toán này gặp khá nhiều luôn. Ví dụ, giả sử bạn có bảng nhân viên, mỗi nhân viên lại có một quản lý. Mà quản lý cũng là nhân viên, nên thông tin của họ cũng nằm trong cùng bảng đó. SELF JOIN sẽ giúp mình ghép nhân viên với quản lý của họ.
Nói một cách chính xác, SELF JOIN là một JOIN bình thường, nhưng mình dùng cùng một bảng hai lần, đặt cho nó hai alias (bí danh) khác nhau để phân biệt các "phiên bản" của bảng đó.
SELF JOIN có thể dùng cho:
- Quan hệ phân cấp: thiết lập quan hệ "cha-con", ví dụ nhân viên và quản lý của họ.
- Phân tích dữ liệu trong bảng: so sánh các bản ghi trong bảng, ví dụ tìm sản phẩm hoặc sự kiện giống nhau.
- Các truy vấn phức tạp với cấu trúc logic lặp lại.
Cú pháp SELF JOIN
Cho dễ hiểu, mình xem luôn cú pháp đơn giản của SELF JOIN nhé:
SELECT
A.column_name,
B.column_name
FROM
table_name A
JOIN
table_name B
ON
A.common_column = B.common_column;
Ở đây:
table_name Avàtable_name Blà cùng một bảng, nhưng có alias khác nhau.A.common_columnvàB.common_columnlà các cột dùng để kết nối bản ghi.
Alias (A và B) là để DBMS "hiểu" bạn đang làm việc với "bản sao" nào của bảng đó.
Ví dụ sử dụng SELF JOIN
Ví dụ 1: danh sách nhân viên và quản lý của họ
Giả sử bạn có bảng employees như sau:
| employee_id | name | manager_id |
|---|---|---|
| 1 | Alex Lin | NULL |
| 2 | Maria Chi | 1 |
| 3 | Otto Song | 1 |
| 4 | Nina Zhao | 2 |
Trong bảng này:
employee_id— mã nhân viên.name— tên nhân viên.manager_id— mã quản lý, cũng làemployee_idcủa một nhân viên khác.
Bài toán: lấy danh sách nhân viên và quản lý của họ.
Làm như này với SELF JOIN nhé:
SELECT
e.name AS employee_name,
m.name AS manager_name
FROM
employees e
LEFT JOIN
employees m
ON
e.manager_id = m.employee_id;
Kết quả:
| employee_name | manager_name |
|---|---|
| Alex Lin | NULL |
| Maria Chi | Alex Lin |
| Otto Song | Alex Lin |
| Nina Zhao | Maria Chi |
Ở đây:
- Bảng
elà "nhân viên". - Bảng
mcũng là "nhân viên", nhưng đóng vai "quản lý".
Alex Lin không có quản lý manager_id = NULL, nên trường manager_name sẽ để trống.
Ví dụ 2: Tìm sản phẩm giống nhau
Giả sử bạn có bảng products:
| product_id | product_name | category |
|---|---|---|
| 1 | Tủ lạnh | Thiết bị |
| 2 | Máy giặt | Thiết bị |
| 3 | Điện thoại thông minh | Gadgets |
| 4 | Máy tính bảng | Gadgets |
Bài toán: tìm các cặp sản phẩm cùng một loại.
Giải với SELF JOIN:
SELECT
p1.product_name AS product_1,
p2.product_name AS product_2
FROM
products p1
JOIN
products p2
ON
p1.category = p2.category
AND
p1.product_id < p2.product_id;
Kết quả:
| product_1 | product_2 |
|---|---|
| Tủ lạnh | Máy giặt |
| Điện thoại thông minh | Máy tính bảng |
Lưu ý điều kiện p1.product_id < p2.product_id. Nó giúp tránh lặp cặp, ví dụ không bị xuất hiện cả Tủ lạnh — Máy giặt và Máy giặt — Tủ lạnh trong kết quả.
Ví dụ 3: Phân tích phân cấp (cha và con)
Thêm một ví dụ nữa nhé. Giả sử bạn có bảng categories:
| category_id | category_name | parent_id |
|---|---|---|
| 1 | Thiết bị | NULL |
| 2 | Gadgets | 1 |
| 3 | Máy tính | 1 |
| 4 | Điện thoại thông minh | 2 |
Ở đây:
category_id— mã loại.category_name— tên loại.parent_id— mã loại cha.
Bài toán: ghép loại với loại cha của nó.
Truy vấn:
SELECT
c1.category_name AS child_category,
c2.category_name AS parent_category
FROM
categories c1
LEFT JOIN
categories c2
ON
c1.parent_id = c2.category_id;
Kết quả:
| child_category | parent_category |
|---|---|
| Thiết bị | NULL |
| Gadgets | Thiết bị |
| Máy tính | Thiết bị |
| Điện thoại thông minh | Gadgets |
Lỗi thường gặp khi dùng SELF JOIN
Quên đặt alias (bí danh): nếu không dùng alias thì không phân biệt được các "bản sao" của bảng.
Tham chiếu vòng lặp: nếu dữ liệu có tham chiếu vòng (ví dụ nhân viên tự làm quản lý cho mình), có thể ra kết quả bất ngờ.
Trùng lặp kết quả: nhớ lọc kết quả (ví dụ dùng p1.product_id < p2.product_id) để tránh bị trùng lặp.
SELF JOIN là công cụ mạnh khi làm việc với dữ liệu, dùng đúng cách sẽ giải quyết được nhiều bài toán phân cấp, liên kết trong bảng và phân tích dữ liệu. Hy vọng giờ bạn đã thấy "selfie" này hữu ích thế nào trong vũ trụ SQL rồi nhé!
GO TO FULL VERSION