Nối SQL là nơi bạn chạy một truy vấn nối nhiều bảng.
Hướng dẫn nối SQL này trình bày các ví dụ cơ bản về phép nối trong SQL, cũng như giới thiệu về các kiểu nối khác nhau.
Kiểu kết hợp SQL
Tiêu chuẩn ANSI SQL chỉ định năm kiểu kết hợp, như được liệt kê trong bảng sau.
Loại tham gia | Mô tả |
---|---|
INNER JOIN | Trả về các hàng khi có ít nhất một hàng trong cả hai bảng phù hợp với điều kiện kết hợp. |
LEFT OUTER JOIN hoặc LEFT JOIN | Trả về các hàng có dữ liệu trong bảng bên trái (bên trái của JOIN từ khóa), ngay cả khi không có hàng phù hợp trong bảng bên phải. |
RIGHT OUTER JOIN hoặc RIGHT JOIN | Trả về các hàng có dữ liệu trong bảng bên phải (bên phải của JOIN từ khóa), ngay cả khi không có hàng phù hợp nào trong bảng bên trái. |
FULL OUTER JOIN hoặc FULL JOIN | Trả về tất cả các hàng, miễn là có dữ liệu khớp trong một trong các bảng. |
CROSS JOIN | Trả về các hàng kết hợp mỗi hàng từ bảng đầu tiên với mỗi hàng từ bảng thứ hai. |
Ngoài ra còn có các điều khoản khác cho các hoạt động kết hợp khác nhau, chẳng hạn như sau:
Tham gia | Mô tả |
---|---|
Tự tham gia | Khi một bảng kết hợp với chính nó. |
Tham gia tự nhiên | Một phép nối ngầm dựa trên các cột chung trong hai bảng đang được nối. |
Tham gia trang bị | Một phép nối chỉ chứa các so sánh bình đẳng trong vị từ phép nối. |
Cú pháp kết hợp SQL
Các phép nối bên trong có thể được chỉ định trong FROM
hoặc WHERE
điều khoản. Các phép nối ngoài và phép nối chéo có thể được chỉ định trong FROM
mệnh đề chỉ.
Để tạo một phép nối SQL trong FROM
, hãy làm một cái gì đó như thế này:
SELECT *
FROM Table1 < JoinType > Table2 [ ON ( JoinCondition ) ]
Nơi JoinType
chỉ định loại kết hợp được thực hiện và JoinCondition
xác định vị từ sẽ được đánh giá cho mỗi cặp hàng được kết hợp.
Để chỉ định một tham gia trong WHERE
, hãy làm một cái gì đó như thế này:
SELECT *
FROM Table1, Table2 [ WHERE ( JoinCondition ) ]
Một lần nữa, JoinCondition
xác định vị từ sẽ được đánh giá cho mỗi cặp hàng được kết hợp.
Ngoài ra, mọi thứ được đặt trong dấu ngoặc vuông ([]
) Là tùy chọn.
Bảng mẫu cho các ví dụ trong Hướng dẫn này
Hầu hết các ví dụ trong hướng dẫn này thực hiện phép nối đối với hai bảng sau.
PetTypes
bảng:
+-------------+-----------+ | PetTypeId | PetType | |-------------+-----------| | 1 | Bird | | 2 | Cat | | 3 | Dog | | 4 | Rabbit | +-------------+-----------+ (4 rows affected)
Pets
bảng:
+---------+-------------+-----------+-----------+------------+ | PetId | PetTypeId | OwnerId | PetName | DOB | |---------+-------------+-----------+-----------+------------| | 1 | 2 | 3 | Fluffy | 2020-11-20 | | 2 | 3 | 3 | Fetch | 2019-08-16 | | 3 | 2 | 2 | Scratch | 2018-10-01 | | 4 | 3 | 3 | Wag | 2020-03-15 | | 5 | 1 | 1 | Tweet | 2020-11-28 | | 6 | 3 | 4 | Fluffy | 2020-09-17 | | 7 | 3 | 2 | Bark | NULL | | 8 | 2 | 4 | Meow | NULL | +---------+-------------+-----------+-----------+------------+ (8 rows affected)
Sự tham gia bên trong
INNER JOIN
trong SQL trả về các hàng khi có ít nhất một hàng trong cả hai bảng phù hợp với điều kiện kết hợp.
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets
INNER JOIN PetTypes
ON Pets.PetTypeId = PetTypes.PetTypeId;
Kết quả:
-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
Để chỉ định một liên kết bên trong trong FROM
, chúng tôi sử dụng INNER JOIN
. Chúng tôi cũng sử dụng ON
từ khóa để xác định vị từ được đánh giá cho mỗi cặp hàng được nối.
Bất kể loại kết hợp nào, chúng tôi đủ điều kiện cho các tên cột của chúng tôi với các tên bảng. Lý do chúng tôi làm điều này là để tránh bất kỳ sự mơ hồ nào về tên cột giữa các bảng. Cả hai bảng đều có thể có các cột cùng tên (như trong ví dụ của chúng tôi) và trong những trường hợp như vậy, DBMS sẽ không biết bạn đang đề cập đến cột nào. Đặt tiền tố tên cột bằng tên bảng của chúng đảm bảo rằng bạn đang tham chiếu đến cột bên phải và ngăn chặn bất kỳ lỗi nào có thể phát sinh từ bất kỳ sự mơ hồ nào về cột mà bạn đang tham chiếu.
Trong ví dụ này, cả hai bảng đều có PetTypeId
cột. Pets.PetTypeId
là một khóa ngoại cho PetTypes.PetTypeId
, là khóa chính cho bảng đó.
Trong ví dụ này, chúng ta có thể thấy rằng tất cả các vật nuôi đều được trả lại, nhưng không phải tất cả các loại vật nuôi đều được trả lại. Không có thỏ nào trong Pets
bảng, và Rabbits
loại vật nuôi không được trả lại.
Lý do Rabbits
loại không được trả lại là do INNER JOIN
chỉ trả về các hàng khi có ít nhất một hàng trong cả hai bảng phù hợp với điều kiện nối. Trong trường hợp này, Rabbits
chỉ có trong một bảng (PetTypes
bảng).
Lưu ý rằng kiểu tham gia là tùy chọn. Do đó, hầu hết (nếu không phải tất cả) DBMS cho phép bạn bỏ qua INNER
từ khóa. Khi bạn bỏ qua điều này (tức là chỉ xác định JOIN
), nó được giả định là một liên kết bên trong.
Do đó, chúng tôi có thể viết lại ví dụ trên thành thế này:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets
JOIN PetTypes
ON Pets.PetTypeId = PetTypes.PetTypeId;
Ngoài ra, như với bất kỳ câu lệnh SQL nào, FROM
mệnh đề có thể ở trên một dòng nếu bạn thích:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets JOIN PetTypes ON Pets.PetTypeId = PetTypes.PetTypeId;
Bí danh
Thực tế phổ biến là sử dụng bí danh bảng khi thực hiện các phép nối SQL. Bí danh giúp làm cho mã ngắn gọn hơn và dễ đọc hơn.
Do đó, chúng tôi có thể thay đổi ví dụ trước thành sau:
SELECT
p.PetName,
pt.PetType
FROM Pets p INNER JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Kết quả:
-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
Tham gia trang bị
Sự tham gia ở trên cũng có thể được gọi là một tham gia tương đương . Một phép nối tương đương là một phép nối chỉ chứa các so sánh bình đẳng trong vị từ phép nối.
Một cách khác để viết phép nối ở trên là như thế này:
SELECT
p.PetName,
pt.PetType
FROM
Pets p,
PetTypes pt
WHERE p.PetTypeId = pt.PetTypeId;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+
Đây là một ví dụ về việc chỉ định một liên kết bên trong trong WHERE
mệnh đề. Chúng tôi chỉ cung cấp danh sách các bảng được phân tách bằng dấu phẩy và sau đó là WHERE
điều kiện. Nếu chúng tôi đã bỏ qua WHERE
điều kiện, chúng tôi đã kết thúc với một CROSS JOIN
.
Nhiều người mới bắt đầu thấy cú pháp trên dễ hiểu hơn nhiều so với INNER JOIN
cú pháp. Tuy nhiên, hãy thoải mái sử dụng cú pháp này nếu bạn thích, hãy lưu ý rằng hầu hết các chuyên gia SQL thích sử dụng INNER JOIN
cú pháp từ ví dụ trước.
Xem SQL Internal Join để biết thêm ví dụ, bao gồm một phép nối bên trong nối 3 bảng.
Tham gia đúng
Còn được gọi là RIGHT OUTER JOIN
, RIGHT JOIN
trả về các hàng có dữ liệu trong bảng bên phải (bên phải của JOIN
từ khóa), ngay cả khi không có hàng phù hợp nào trong bảng bên trái.
SELECT
p.PetName,
pt.PetType
FROM Pets p
RIGHT JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Tweet | Bird | | Fluffy | Cat | | Scratch | Cat | | Meow | Cat | | Fetch | Dog | | Wag | Dog | | Fluffy | Dog | | Bark | Dog | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
Trong trường hợp này, chúng tôi có thêm một PetType
giá trị - Rabbit
- mặc dù không có vật nuôi nào trong Pets
bảng loại đó. Điều này dẫn đến NULL
giá trị trong PetName
cột chống lại Rabbit
.
Xem SQL Right Join để biết thêm ví dụ, bao gồm một phép nối phải nối 3 bảng.
Tham gia bên trái
Còn được gọi là LEFT OUTER JOIN
, SQL LEFT JOIN
trả về các hàng có dữ liệu trong bảng bên trái (bên trái của JOIN
từ khóa), ngay cả khi không có hàng nào phù hợp trong bảng bên phải.
Điều này ngược lại với RIGHT JOIN
.
Nếu chúng ta thay đổi ví dụ trước để sử dụng kết nối bên trái, chúng ta sẽ nhận được kết quả sau.
SELECT
p.PetName,
pt.PetType
FROM Pets p
LEFT JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
Trong trường hợp cụ thể này, kết quả của chúng tôi giống như với phép nối bên trong.
Tuy nhiên, nếu chúng ta hoán đổi thứ tự bảng trong FROM
, chúng ta sẽ nhận được một kết quả tương tự với phép nối phải trong ví dụ trước.
SELECT
p.PetName,
pt.PetType
FROM PetTypes pt
LEFT JOIN Pets p
ON p.PetTypeId = pt.PetTypeId;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Tweet | Bird | | Fluffy | Cat | | Scratch | Cat | | Meow | Cat | | Fetch | Dog | | Wag | Dog | | Fluffy | Dog | | Bark | Dog | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
Vì vậy, bạn có thể thấy rằng bất kỳ sự khác biệt kết quả nào giữa các phép nối trái và phải chỉ phụ thuộc vào cách bạn sắp xếp các cột trong FROM
mệnh đề.
Xem SQL Left Join để biết thêm ví dụ, bao gồm một phép nối bên trái kết hợp 3 bảng.
Tham gia đầy đủ
SQL FULL JOIN
(hoặc FULL OUTER JOIN
) trả về tất cả các hàng, miễn là có dữ liệu khớp trong một trong các bảng.
Nói cách khác, nó giống như có cả phép tham gia bên trái và bên phải trong một phép nối.
Dưới đây là một ví dụ về tham gia đầy đủ.
SELECT
p.PetName,
pt.PetType
FROM Pets p
FULL JOIN PetTypes pt
ON p.PetTypeId = pt.PetTypeId;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
Điều này trả về cùng một kết quả mà chúng tôi nhận được với phép nối bên phải, nhưng nó sẽ trả lại một kết quả khác nếu có một hàng trong bảng bên trái không có giá trị tương ứng trong bảng bên phải.
Hãy hoán đổi tên bảng và chạy lại.
SELECT
p.PetName,
pt.PetType
FROM PetTypes pt
FULL JOIN Pets p
ON p.PetTypeId = pt.PetTypeId;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Tweet | Bird | | Fluffy | Cat | | Scratch | Cat | | Meow | Cat | | Fetch | Dog | | Wag | Dog | | Fluffy | Dog | | Bark | Dog | | NULL | Rabbit | +-----------+-----------+ (9 rows affected)
Kết quả tương tự.
Xem SQL Full Join để biết thêm ví dụ, bao gồm một phép nối đầy đủ nối 3 bảng.
Thập giá tham gia
SQL CROSS JOIN
trả về các hàng kết hợp mỗi hàng từ bảng đầu tiên với mỗi hàng từ bảng thứ hai.
Nói cách khác, nó trả về tích số Descartes của các hàng từ các bảng trong phép nối.
SELECT
p.PetName,
pt.PetType
FROM Pets p
CROSS JOIN PetTypes pt;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Bird | | Fetch | Bird | | Scratch | Bird | | Wag | Bird | | Tweet | Bird | | Fluffy | Bird | | Bark | Bird | | Meow | Bird | | Fluffy | Cat | | Fetch | Cat | | Scratch | Cat | | Wag | Cat | | Tweet | Cat | | Fluffy | Cat | | Bark | Cat | | Meow | Cat | | Fluffy | Dog | | Fetch | Dog | | Scratch | Dog | | Wag | Dog | | Tweet | Dog | | Fluffy | Dog | | Bark | Dog | | Meow | Dog | | Fluffy | Rabbit | | Fetch | Rabbit | | Scratch | Rabbit | | Wag | Rabbit | | Tweet | Rabbit | | Fluffy | Rabbit | | Bark | Rabbit | | Meow | Rabbit | +-----------+-----------+ (32 rows affected)
Như bạn có thể tưởng tượng, điều này có thể rất nguy hiểm nếu bạn chạy nó với các bảng sai.
Nó cũng giống như làm điều này:
SELECT
p.PetName,
pt.PetType
FROM Pets p, PetTypes pt;
Bạn có thể thêm WHERE
mệnh đề với một phép nối chéo, điều này sẽ biến nó thành một phép nối bên trong.
Như thế này:
SELECT
p.PetName,
pt.PetType
FROM Pets p
CROSS JOIN PetTypes pt
WHERE p.PetTypeId = pt.PetTypeId;
Kết quả:
+-----------+-----------+ | PetName | PetType | |-----------+-----------| | Fluffy | Cat | | Fetch | Dog | | Scratch | Cat | | Wag | Dog | | Tweet | Bird | | Fluffy | Dog | | Bark | Dog | | Meow | Cat | +-----------+-----------+ (8 rows affected)
Xem SQL Cross Join để biết thêm ví dụ.
Sự tham gia tự nhiên
SQL NATURAL JOIN
là một kiểu nối tương đương trong đó vị từ nối phát sinh ngầm định bằng cách so sánh tất cả các cột trong cả hai bảng có cùng tên cột trong các bảng đã nối.
Tập kết quả chỉ chứa một cột cho mỗi cặp cột được đặt tên bằng nhau. Nếu không tìm thấy cột nào có cùng tên, kết quả sẽ là một phép nối chéo.
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets NATURAL JOIN PetTypes;
Kết quả:
petname | pettype ---------+--------- Fluffy | Cat Fetch | Dog Scratch | Cat Wag | Dog Tweet | Bird Fluffy | Dog Bark | Dog Meow | Cat (8 rows)
Trên thực tế, phép nối tự nhiên không thực sự là một loại phép nối, theo tiêu chuẩn ANSI. Đây là một từ khóa mà bạn có thể tùy chọn chèn để làm cho việc tham gia trở thành một kết nối tự nhiên.
Do đó, chúng ta có thể thay đổi ví dụ trên thành NATURAL INNER JOIN
nếu chúng tôi muốn:
SELECT
Pets.PetName,
PetTypes.PetType
FROM Pets NATURAL INNER JOIN PetTypes;
Như đã đề cập trước đó, liên kết bên trong là loại liên kết mặc định, vì vậy nếu bạn bỏ qua loại liên kết (ví dụ:INNER
, LEFT
, RIGHT
, v.v.), thì nó được coi như một liên kết bên trong.
Nếu định dạng của các kết quả này trông khác với các kết quả trước đó, thì đó là do tôi phải chuyển sang PostgreSQL để chạy truy vấn này. Tôi đã chạy các ví dụ trước đó trong SQL Server, nhưng SQL Server không hỗ trợ kết hợp tự nhiên.
Xem SQL Natural Join để biết thêm ví dụ, bao gồm một phép nối tự nhiên nối 3 bảng.
Tự tham gia
SQL SELF JOIN
đang tham gia một bảng với chính nó.
Một ví dụ cổ điển về tự tham gia là trong bảng Nhân viên. Trong một bảng như vậy, một nhân viên có thể báo cáo cho một nhân viên khác. Do đó, bạn có thể sử dụng tự nối để tham gia vào bảng trên cột ID nhân viên và cột ID người quản lý.
Giả sử chúng ta có bảng sau:
+--------------+-------------+------------+-------------+ | EmployeeId | FirstName | LastName | ReportsTo | |--------------+-------------+------------+-------------| | 1 | Homer | Connery | NULL | | 2 | Bart | Pitt | 1 | | 3 | Maggie | Griffin | 1 | | 4 | Peter | Farnsworth | 2 | | 5 | Marge | Morrison | NULL | | 6 | Lisa | Batch | 5 | | 7 | Dave | Zuckerberg | 6 | | 8 | Vlad | Cook | 7 | +--------------+-------------+------------+-------------+
Chúng ta có thể tự tham gia trên bảng này để trả lại tất cả nhân viên và người quản lý của họ.
SELECT
CONCAT(e1.FirstName, ' ', e1.LastName) AS Employee,
CONCAT(e2.FirstName, ' ', e2.LastName) AS Manager
FROM Employees e1
LEFT JOIN Employees e2
ON e1.ReportsTo = e2.EmployeeId;
Kết quả:
+------------------+-----------------+ | Employee | Manager | |------------------+-----------------| | Homer Connery | | | Bart Pitt | Homer Connery | | Maggie Griffin | Homer Connery | | Peter Farnsworth | Bart Pitt | | Marge Morrison | | | Lisa Batch | Marge Morrison | | Dave Zuckerberg | Lisa Batch | | Vlad Cook | Dave Zuckerberg | +------------------+-----------------+
Xem SQL Self Join để biết thêm ví dụ.