Join (SQL)

Bách khoa toàn thư mở Wikipedia
Bước tới: menu, tìm kiếm

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.

Ví dụ trên bảng[sửa | sửa mã nguồn]

Những ví dụ dưới đây về phép kết hợp sử dụng 2 bảng sau:

Bảng "employee"
LastName DepartmentID
Smith 34
Jones 33
Robinson 34
Jasper 36
Steinberg 33
Rafferty 31


Bảng "department"
DepartmentName DepartmentID
Sales 31
Engineering 33
Clerical 34
Marketing 35

Để 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.

Các hình thức kết hợp[sửa | sửa mã nguồn]

Kết nội[sửa | sửa mã nguồn]

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.

Kết ngoại bên trái[sửa | sửa mã nguồn]

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 quả ở 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, một số hệ quản trị CSDL không hiểu dấu (+). Sau đây là mã lỗi (Server: Msg 170, Level 15, State 1, Line 3 Line 3: Incorrect syntax near ')')

Kết ngoại bên phải[sửa | sửa mã nguồn]

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 phả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 |
+-----------+--------------+----------------+--------------+

Kết ngoại đủ[sửa | sửa mã nguồn]

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

Kết chéo[sửa | sửa mã nguồn]


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)

Xem thêm[sửa | sửa mã nguồn]

Tổng quát[sửa | sửa mã nguồn]

Tham khảo[sửa | sửa mã nguồn]