SELF JOIN là join một bảng với chính nó, dùng khi dữ liệu có quan hệ đệ quy (cấp bậc, cha-con, so sánh nội bộ).
Ví dụ minh họa
Tạo bảng quốc gia với năm và xếp hạng:
mysql> CREATE TABLE SelfJoinDemo (
-> Id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> CountryName VARCHAR(20),
-> CountryRank INT,
-> `Year` VARCHAR(10)
-> );
Chèn dữ liệu (UK xuất hiện 2 lần với năm khác nhau):
mysql> INSERT INTO SelfJoinDemo(CountryName, CountryRank, `Year`) VALUES('US', 1, '2016');
mysql> INSERT INTO SelfJoinDemo(CountryName, CountryRank, `Year`) VALUES('UK', 5, '2013');
mysql> INSERT INTO SelfJoinDemo(CountryName, CountryRank, `Year`) VALUES('France', 45, '2010');
mysql> INSERT INTO SelfJoinDemo(CountryName, CountryRank, `Year`) VALUES('Turkey', 3, '2000');
mysql> INSERT INTO SelfJoinDemo(CountryName, CountryRank, `Year`) VALUES('Japan', 78, '1995');
mysql> INSERT INTO SelfJoinDemo(CountryName, CountryRank, `Year`) VALUES('Romania', 110, '2007');
mysql> INSERT INTO SelfJoinDemo(CountryName, CountryRank, `Year`) VALUES('UK', 3, '2000');
Dữ liệu:
+----+-------------+-------------+------+ | Id | CountryName | CountryRank | Year | +----+-------------+-------------+------+ | 1 | US | 1 | 2016 | | 2 | UK | 5 | 2013 | | 3 | France | 45 | 2010 | | 4 | Turkey | 3 | 2000 | | 5 | Japan | 78 | 1995 | | 6 | Romania | 110 | 2007 | | 7 | UK | 3 | 2000 | +----+-------------+-------------+------+
SELF JOIN: Tìm năm của US và các quốc gia cùng năm
mysql> SELECT DISTINCT t1.CountryName, t2.Year
-> FROM SelfJoinDemo AS t1, SelfJoinDemo AS t2
-> WHERE t1.Year = t2.Year
-> AND t1.CountryName = 'US';
Kết quả:
+-------------+------+ | CountryName | Year | +-------------+------+ | US | 2016 | +-------------+------+
Chỉ US có năm 2016, nên chỉ trả về US.
Ứng dụng thực tế của SELF JOIN
- Cây tổ chức: Nhân viên - Quản lý (manager_id tham chiếu employee_id)
- Danh mục đa cấp: Category - Parent Category
- So sánh hàng trong cùng bảng: Tìm cặp giá trị thỏa điều kiện
- Phân tích chuỗi thời gian: So sánh kỳ này với kỳ trước
Ví dụ nhân viên - quản lý
SELECT e.Name AS Employee, m.Name AS Manager FROM Employees e LEFT JOIN Employees m ON e.ManagerId = m.EmployeeId;