Join (SQL)
Bách khoa toàn thư mở Wikipedia
Một từ khóa join kết nối nhiều bản ghi từ 2 bảng dữ liệu trong 1 cơ sở dữ liệu quan hệ và kết quả được đưa vào 1 bảng (tạm). Trong ngôn ngữ truy vấn theo cấu trúc (SQL) có 3 loại kết hợp sau: nội, ngoại và chéo. Kết ngoại được chia ra thêm thành kết ngoại bên trái (left outer join), kết ngoại bên phải (right outer join), và kết ngoại đủ (full outer join).
Về mặt toán học, phép kết hợp là 1 cấu tạo quan hệ, 1 thao tác cơ bản trong đại số quan hệ và tổng quát hóa và là khái quát hóa của cấu tạo hàm.
Mục lục |
[sửa] Ví dụ trên bảng
Những ví dụ dưới đây về phép kết hợp sử dụng 2 bảng sau:
|
|
Để minh họa, ta cần chú ý rằng DepartmentID của nhân viên Jasper không có dòng tương ứng nào trong bảng department, và phòng Marketing thì không có dòng tương ứng trong bảng employee.
[sửa] Các hình thức kết hợp
[sửa] Kết nội
Một phép kết nội (inner join) thực chất là tìm giao của 2 bảng dữ liệu. Đây là loại kết hợp thường đươc dùng nhất và được xem như là phép kết hợp mặc định. Ví dụ dưới đây về phép kết hợp trích tất cả các bản ghi trong bảng dữ liệu A (employee) và tìm những bản ghi tương ứng trong bảng B (department). Nếu không tìm được, những bản ghi trong A sẽ không được đưa vào kết quả. Nếu có nhiều kết quả tìm được trong B tương ứng với vị từ, thì 1 dòng sẽ được trả về ứng với mỗi vị từ (giá trị ở bảng A sẽ được lặp).
Cần đặc biệt chú ý khi kết hợp những bảng trên những cột mà có thể là NULL vì giá trị NULL sẽ không bao giờ có tương ứng. Xem giải pháp ở Phép Kết Ngoại Trái và Phép Kết Ngoại phải
Ví dụ về phép kết nội (cú pháp chuẩn ANSI 92):
SELECT * FROM employee INNER JOIN department ON employee.DepartmentID = department.DepartmentID
Ví dụ về phép kết nội (cú pháp không chuẩn):
SELECT * FROM employee, department WHERE employee.DepartmentID = department.DepartmentID
Kết quả kết hợp:
+-----------+--------------+----------------+--------------+ | LastName | DepartmentID | DepartmentName | DepartmentID | +-----------+--------------+----------------+--------------+ | Smith | 34 | Clerical | 34 | | Jones | 33 | Engineering | 33 | | Robinson | 34 | Clerical | 34 | | Steinberg | 33 | Engineering | 33 | | Rafferty | 31 | Sales | 31 | +-----------+--------------+----------------+--------------+
Chú ý rằng nhân viên Jasper và phòng Marketing không xuất hiện. Không một bản nào trong những bản này có dòng tương ứng trong bảng kết hợp của chúng, nên đã bị loại ra khỏi kết quả của phép kết nội này.
[sửa] Kết ngoại bên trái
Một phép kết ngoại bên trái (left outer join) khác rất nhiều với 1 phép kết nội. Thay vì giới hạn những kết quả thu được trong cả 2 bảng, nó chỉ giới hạn đối với những kết qua ở bảng bên trái (A). Nghĩa là nếu mệnh đề ON không có bản ghi tương ứng bên bảng B, 1 dòng trong kết quả vẫn được trả về nhưng với giá trị NULL cho mỗi cột trong bảng B.
Nó trả về tất cả những giá trị từ bản bên trái + (những giá trị tương ứng với bảng bên phải hoặc là (null khi những giá trị ở bảng bên phải không tương ứng)
Chẳng hạn, nó cho phép ta tìm phòng ban của nhân viên, nhưng vẫn trả về nhân viên ngay cả khi phòng ban của người ấy là NULL hoặc không tồn tại. Ví dụ ở trên sẽ bỏ qua những nhân viên trong phòng ban không tồn tại.
Ví dụ về phép kết ngoại bên trái (cú pháp chuẩn ANSI 92):
SELECT distinct * FROM employee LEFT OUTER JOIN department ON employee.DepartmentID = department.DepartmentID
Ví dụ về phép kết ngoại bên trái (cú pháp không chuẩn):
SELECT * FROM employee, department WHERE employee.DepartmentID = department.DepartmentID(+)
+-----------+--------------+----------------+--------------+ | LastName | DepartmentID | DepartmentName | DepartmentID | +-----------+--------------+----------------+--------------+ | Smith | 34 | Clerical | 34 | | Jones | 33 | Engineering | 33 | | Robinson | 34 | Clerical | 34 | | Jasper | 36 | NULL | NULL | | Steinberg | 33 | Engineering | 33 | | Rafferty | 31 | Sales | 31 | +-----------+--------------+----------------+--------------+
Trong cú pháp không chuẩn, dấu (+) ngụ ý rằng bảng department phải được mở rộng (bằng giá trị NULL) cho những dòng không tương ứng tồn tại trong bảng employee. Dấu (+) chỉ được dùng trong một số hệ quản trị CSDL, có hệ quản trị CSDL dùng dấu (+) nó sẽ không hiểu. Sau đây là mã lỗi (Server: Msg 170, Level 15, State 1, Line 3 Line 3: Incorrect syntax near ')')
[sửa] Kết ngoại bên phải
Một phép kết ngoại bên phải (right outer join) hầu như tương tự với phép kết ngoại bên trái, trừ 1 điều là thứ tự các bảng đổi lại. Mỗi bản ghi từ bảng bên phải, B hoặc department sẽ được trả về và giá trị NULL sẽ được trả về cho những dòng mà không có bản ghi tương ứng bên bảng A.
Nó trả về tất cả những giá trị từ bảng bên phải + giá trị tương ứng từ bảng bên trái (hoặc null)
Ví dụ về phép kết ngoại bên phải (cú pháp chuẩn ANSI 92):
SELECT * FROM employee RIGHT OUTER JOIN department ON employee.DepartmentID = department.DepartmentID
Ví dụ về phép kết ngoại bên trái (cú pháp không chuẩn):
SELECT * FROM employee, department WHERE employee.DepartmentID(+) = department.DepartmentID
+-----------+--------------+----------------+--------------+ | LastName | DepartmentID | DepartmentName | DepartmentID | +-----------+--------------+----------------+--------------+ | Smith | 34 | Clerical | 34 | | Jones | 33 | Engineering | 33 | | Robinson | 34 | Clerical | 34 | | Steinberg | 33 | Engineering | 33 | | Rafferty | 31 | Sales | 31 | | NULL | NULL | Marketing | 35 | +-----------+--------------+----------------+--------------+
[sửa] Kết ngoại đủ
[sửa] Full outer join
Một phép kết ngoại đủ (full outer join) kết hợp cả kết quả của cả phép kết ngoại bên trái và phép kết ngoại bên phải. Những phép kết này đưa ra bản ghi của cả 2 bảng dữ liệu, và lấp đầy những dòng tương ứng bị thiếu của cả 2 phía bằng NULLs.
Một vài hệ cơ sở dữ liệu không hỗ trợ chức năng này, nhưng nó có thể được thay thế bằng việc dùng phép kết ngoại bên trái và bên phải và phép hợp (union). (Xem dưới đây)
Ví dụ về phép kết ngoại đủ (cú pháp chuẩn ANSI 92):
SELECT * FROM employee FULL OUTER JOIN department ON employee.DepartmentID = department.DepartmentID
+-----------+--------------+----------------+--------------+ | LastName | DepartmentID | DepartmentName | DepartmentID | +-----------+--------------+----------------+--------------+ | Smith | 34 | Clerical | 34 | | Jones | 33 | Engineering | 33 | | Robinson | 34 | Clerical | 34 | | Jasper | 36 | NULL | NULL | | Steinberg | 33 | Engineering | 33 | | Rafferty | 31 | Sales | 31 | | NULL | NULL | Marketing | 35 | +-----------+--------------+----------------+--------------+
Cùng 1 ví dụ, cho những cơ sở dữ liệu không hỗ trợ phép kết ngoại đủ:
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName, department.DepartmentID FROM employee LEFT JOIN department ON employee.DepartmentID = department.DepartmentID UNION SELECT employee.LastName, employee.DepartmentID, department.DepartmentName, department.DepartmentID FROM employee RIGHT JOIN department ON employee.DepartmentID = department.DepartmentID WHERE employee.DepartmentID IS NULL
[sửa] Kết chéo
Mặc dù không được sử dụng thường xuyên, một phép kết chéo (cross join) là cơ sở mà dựa trên đó phép kết nội được tạo nên. Một phép kết chéo trả về tích Descartes của những tập hợp các dòng từ những bảng được kết.
Câu SQL dùng cho phép kết chéo liệt kê những bảng dữ liệu sẽ được kết (FROM
), nhưng không bao gồm bất cứ vị từ lọc nào (WHERE
).
Ví dụ về phép kết chéo (cú pháp chuẩn ANSI 92):
SELECT * FROM employee CROSS JOIN department;
Ví dụ về phép kết chéo (cú pháp thay thế):
SELECT * FROM employee, department;
+-----------+---------------+----------------+--------------+ | LastName | DepartmentID | DepartmentName | DepartmentID | +-----------+---------------+----------------+--------------+ | Smith | 34 | Sales | 31 | | Smith | 34 | Engineering | 33 | | Smith | 34 | Clerical | 34 | | Smith | 34 | Marketing | 35 | | Jones | 33 | Sales | 31 | | Jones | 33 | Engineering | 33 | | Jones | 33 | Clerical | 34 | | Jones | 33 | Marketing | 35 | | Robinson | 34 | Sales | 31 | | Robinson | 34 | Engineering | 33 | | Robinson | 34 | Clerical | 34 | | Robinson | 34 | Marketing | 35 | | Jasper | 36 | Sales | 31 | | Jasper | 36 | Engineering | 33 | | Jasper | 36 | Clerical | 34 | | Jasper | 36 | Marketing | 35 | | Steinberg | 33 | Sales | 31 | | Steinberg | 33 | Engineering | 33 | | Steinberg | 33 | Clerical | 34 | | Steinberg | 33 | Marketing | 35 | | Rafferty | 31 | Sales | 31 | | Rafferty | 31 | Engineering | 33 | | Rafferty | 31 | Clerical | 34 | | Rafferty | 31 | Marketing | 35 | +-----------+---------------+----------------+--------------+
Ta có thể thấy phép kết chéo không tìm những bản ghi tương ứng. Phép kết này ít khi được dùng, ngoại trừ để phát sinh tất cả những kết hợp có khả năng của các bản ghi từ các bảng dữ liệu mà không chia sẻ phần tử chung.
Nếu A và B là 2 tập hợp thì phép kết chéo tạo ra |A| x |B| bản ghi ở kết quả (với |X| là lực lượng (số phần tử) của tập hợp X)