Giới thiệu
Việc tách dữ liệu liên quan thành các bảng riêng biệt có thể có lợi từ quan điểm về tính nhất quán, tính linh hoạt và một số loại hiệu suất nhất định. Tuy nhiên, bạn vẫn cần một cách hợp lý để tích hợp lại các bản ghi khi thông tin liên quan trải dài trên nhiều bảng.
Trong cơ sở dữ liệu quan hệ, tham gia đưa ra một cách để kết hợp các bản ghi trong hai hoặc nhiều bảng dựa trên các giá trị trường chung. Các loại liên kết khác nhau có thể đạt được các kết quả khác nhau tùy thuộc vào cách xử lý các hàng không khớp. Trong hướng dẫn này, chúng ta sẽ thảo luận về các loại liên kết khác nhau mà PostgreSQL cung cấp và cách bạn có thể sử dụng chúng để kết hợp dữ liệu bảng từ nhiều nguồn.
Liên kết là gì?
Nói tóm lại, tham gia là một cách hiển thị dữ liệu từ nhiều bảng. Họ thực hiện điều này bằng cách ghép các bản ghi lại với nhau từ các nguồn khác nhau dựa trên các giá trị phù hợp trong các cột nhất định. Mỗi hàng kết quả bao gồm một bản ghi từ bảng đầu tiên kết hợp với một hàng từ bảng thứ hai, dựa trên một hoặc nhiều cột trong mỗi bảng có cùng giá trị.
Cú pháp cơ bản của phép nối trông giống như sau:
SELECT *FROM <first_table><join_type> <second_table> <join_condition>;
Trong một phép nối, mỗi hàng kết quả được tạo bằng cách bao gồm tất cả các cột của bảng đầu tiên, theo sau là tất cả các cột từ bảng thứ hai. SELECT
một phần của truy vấn có thể được sử dụng để chỉ định các cột chính xác mà bạn muốn hiển thị.
Nhiều hàng có thể được tạo từ các bảng ban đầu nếu giá trị trong các cột được sử dụng để so sánh không phải là duy nhất. Ví dụ:hãy tưởng tượng bạn có một cột được so sánh từ bảng đầu tiên có hai bản ghi có giá trị là "màu đỏ". Đối sánh với cột này là một cột từ bảng thứ hai có ba hàng với giá trị đó. Phép nối sẽ tạo ra sáu hàng khác nhau cho giá trị đó đại diện cho các kết hợp khác nhau có thể đạt được.
Loại liên kết và các điều kiện kết hợp xác định cách mỗi hàng được hiển thị được xây dựng. Điều này ảnh hưởng đến những gì sẽ xảy ra với các hàng từ mỗi bảng có và không không có một trận đấu với điều kiện tham gia.
Để thuận tiện, nhiều phép nối khớp với khóa chính trên một bảng với khóa ngoại được liên kết trên bảng thứ hai. Mặc dù khóa chính và khóa ngoại chỉ được sử dụng bởi hệ thống cơ sở dữ liệu để duy trì đảm bảo tính nhất quán, nhưng mối quan hệ của chúng thường khiến chúng trở thành ứng cử viên sáng giá cho các điều kiện tham gia.
Các loại liên kết khác nhau
Có nhiều kiểu nối khác nhau, mỗi kiểu sẽ có khả năng tạo ra các kết quả khác nhau. Hiểu cách xây dựng từng loại sẽ giúp bạn xác định loại nào phù hợp với các tình huống khác nhau.
Tham gia bên trong
Tham gia mặc định được gọi là liên kết bên trong . Trong PostgreSQL, điều này có thể được chỉ định bằng cách sử dụng INNER JOIN
hoặc chỉ đơn giản là JOIN
.
Đây là một ví dụ điển hình thể hiện cú pháp của một phép nối bên trong:
SELECT *FROM table_1[INNER] JOIN table_2 ON table_1.id = table_2.table_1_id;
Phép nối bên trong là kiểu phép nối hạn chế nhất vì nó chỉ hiển thị các hàng được tạo bằng cách kết hợp các hàng từ mỗi bảng. Bất kỳ hàng nào trong bảng cấu thành không có phần đối ứng phù hợp trong bảng khác sẽ bị xóa khỏi kết quả. Ví dụ:nếu bảng đầu tiên có giá trị "xanh lam" trong cột so sánh và bảng thứ hai không có bản ghi nào có giá trị đó, thì hàng đó sẽ bị loại bỏ khỏi đầu ra.
Nếu bạn biểu diễn kết quả dưới dạng biểu đồ Venn của các bảng thành phần, một phép nối bên trong cho phép bạn biểu diễn vùng chồng lấn của hai vòng tròn. Không có giá trị nào chỉ tồn tại trong một trong các bảng được hiển thị.
Tham gia trái
Một phép nối bên trái là phép nối hiển thị tất cả các bản ghi được tìm thấy trong một phép nối bên trong, cộng với tất cả chưa khớp hàng từ bảng đầu tiên. Trong PostgreSQL, điều này có thể được chỉ định dưới dạng LEFT OUTER JOIN
hoặc chỉ là một LEFT JOIN
.
Cú pháp cơ bản của phép nối bên trái tuân theo mẫu sau:
SELECT *FROM table_1LEFT JOIN table_2 ON table_1.id = table_2.table_1_id;
Một phép nối bên trái được xây dựng bằng cách thực hiện một phép nối bên trong trước tiên để tạo các hàng từ tất cả các bản ghi phù hợp trong cả hai bảng. Sau đó, các bản ghi chưa khớp từ bảng đầu tiên cũng được bao gồm. Vì mỗi hàng trong một phép nối bao gồm các cột của cả hai bảng, nên các cột không khớp nhau sử dụng NULL
làm giá trị cho tất cả các cột trong bảng thứ hai.
Nếu bạn biểu diễn kết quả dưới dạng biểu đồ Venn của các bảng thành phần, phép nối bên trái cho phép bạn biểu diễn toàn bộ vòng tròn bên trái. Các phần của hình tròn bên trái được biểu thị bằng phần giao nhau giữa hai vòng tròn sẽ có thêm dữ liệu được bổ sung bởi bảng bên phải.
Tham gia phù hợp
Một phép nối phải là phép nối hiển thị tất cả các bản ghi được tìm thấy trong một phép nối bên trong, cộng với tất cả chưa khớp hàng từ bảng thứ hai. Trong PostgreSQL, điều này có thể được chỉ định dưới dạng RIGHT OUTER JOIN
hoặc chỉ là một RIGHT JOIN
.
Cú pháp cơ bản của phép nối phải tuân theo mẫu sau:
SELECT *FROM table_1RIGHT JOIN table_2 ON table_1.id = table_2.table_1_id;
Một phép nối phải được xây dựng bằng cách thực hiện một phép nối bên trong trước tiên để tạo các hàng từ tất cả các bản ghi phù hợp trong cả hai bảng. Sau đó, các bản ghi chưa khớp từ bảng thứ hai cũng được bao gồm. Vì mỗi hàng trong một phép nối bao gồm các cột của cả hai bảng, nên các cột không khớp nhau sử dụng NULL
làm giá trị cho tất cả các cột trong bảng đầu tiên.
Nếu bạn biểu diễn kết quả dưới dạng biểu đồ Venn của các bảng thành phần, phép nối bên phải cho phép bạn biểu diễn toàn bộ vòng tròn bên phải. Các phần của vòng tròn bên phải được biểu thị bằng giao điểm giữa hai vòng tròn sẽ có thêm dữ liệu được bổ sung bởi bảng bên trái.
Tham gia đầy đủ
Một phép nối đầy đủ là một phép nối hiển thị tất cả các bản ghi được tìm thấy trong một phép nối bên trong, cộng với tất cả chưa khớp hàng từ cả hai bảng thành phần. Trong PostgreSQL, điều này có thể được chỉ định là FULL OUTER JOIN
hoặc chỉ là một FULL JOIN
.
Cú pháp cơ bản của phép nối đầy đủ tuân theo mẫu sau:
SELECT *FROM table_1FULL JOIN table_2 ON table_1.id = table_2.table_1_id;
Một phép nối đầy đủ được xây dựng bằng cách thực hiện một phép nối bên trong trước tiên để tạo các hàng từ tất cả các bản ghi phù hợp trong cả hai bảng. Sau đó, các bản ghi chưa khớp từ cả hai bảng cũng được bao gồm. Vì mỗi hàng trong một phép nối bao gồm các cột của cả hai bảng, nên các cột không khớp nhau sử dụng NULL
làm giá trị cho tất cả các cột trong bảng khác chưa được so khớp.
Nếu bạn biểu diễn kết quả dưới dạng biểu đồ Venn của các bảng thành phần, một phép nối đầy đủ cho phép bạn biểu diễn toàn bộ cả hai vòng tròn thành phần. Giao điểm của hai đường tròn sẽ có các giá trị được cung cấp bởi mỗi bảng thành phần. Các phần của vòng tròn bên ngoài vùng chồng chéo sẽ có các giá trị từ bảng mà chúng thuộc về, bằng cách sử dụng NULL
để điền vào các cột được tìm thấy trong bảng khác.
Tham gia chéo
Một tham gia đặc biệt được gọi là CROSS JOIN
cũng có sẵn. Phép nối chéo không sử dụng bất kỳ phép so sánh nào để xác định xem các hàng trong mỗi bảng có khớp với nhau hay không. Thay vào đó, kết quả được tạo bằng cách chỉ cần thêm từng hàng từ bảng đầu tiên vào từng hàng của bảng thứ hai.
Điều này tạo ra một tích Descartes của các hàng trong hai hoặc nhiều bảng. Trên thực tế, kiểu nối này kết hợp các hàng từ mỗi bảng một cách vô điều kiện. Vì vậy, nếu mỗi bảng có ba hàng, bảng kết quả sẽ có chín hàng chứa tất cả các cột từ cả hai bảng.
Ví dụ:nếu bạn có một bảng được gọi là t1
được kết hợp với một bảng có tên t2
, mỗi hàng có r1
, r2
và r3
, kết quả sẽ là chín hàng được kết hợp như vậy:
t1.r1 + t2.r1t1.r1 + t2.r2t1.r1 + t2.r3t1.r2 + t2.r1t1.r2 + t2.r2t1.r2 + t2.r3t1.r3 + t2.r1t1.r3 + t2.r2t1.r3 + t2.r3
Tự tham gia
Một liên kết tự là bất kỳ liên kết nào kết hợp các hàng của bảng với chính nó. Có thể không rõ ràng ngay lập tức điều này có thể hữu ích như thế nào, nhưng nó thực sự có nhiều ứng dụng phổ biến.
Thông thường, các bảng mô tả các thực thể có thể thực hiện nhiều vai trò trong mối quan hệ với nhau. Ví dụ:nếu bạn có một bảng gồm people
, mỗi hàng có thể chứa một mother
cột tham chiếu đến people
khác trong bàn. Tự nối sẽ cho phép bạn ghép các hàng khác nhau này lại với nhau bằng cách nối phiên bản thứ hai của bảng với phiên bản đầu tiên nơi các giá trị này khớp với nhau.
Vì bản thân tham chiếu cùng một bảng hai lần, nên bí danh bảng được yêu cầu để phân biệt các tham chiếu. Chẳng hạn, trong ví dụ trên, bạn có thể kết hợp hai trường hợp của people
bảng sử dụng bí danh people AS children
và people AS mothers
. Bằng cách đó, bạn có thể chỉ định phiên bản nào của bảng mà bạn đang đề cập đến khi xác định các điều kiện kết hợp.
Đây là một ví dụ khác, lần này thể hiện mối quan hệ giữa nhân viên và người quản lý:
SELECT *FROM people AS employeeJOIN people AS manager ON employee.manager_id = manager.id;
Điều kiện tham gia
Khi kết hợp các bảng, điều kiện nối xác định cách các hàng sẽ được khớp với nhau để tạo thành kết quả tổng hợp. Tiền đề cơ bản là xác định các cột trong mỗi bảng phải khớp để phép nối xảy ra trên hàng đó.
ON
mệnh đề
Cách chuẩn nhất để xác định các điều kiện cho phép nối bảng là ON
mệnh đề. ON
mệnh đề sử dụng dấu bằng để chỉ định các cột chính xác từ mỗi bảng sẽ được so sánh để xác định khi nào một phép nối có thể xảy ra. PostgreSQL sử dụng các cột được cung cấp để ghép các hàng từ mỗi bảng lại với nhau.
ON
mệnh đề dài nhất, nhưng cũng linh hoạt nhất trong số các điều kiện nối có sẵn. Nó cho phép tính cụ thể bất kể tên cột của mỗi bảng được kết hợp với nhau như thế nào.
Cú pháp cơ bản của ON
mệnh đề giống như sau:
SELECT *FROM table1JOIN table2ON table1.id = table2.ident;
Đây, các hàng từ table1
và table2
sẽ được kết hợp bất cứ khi nào id
cột từ table1
khớp với ident
cột từ table2
. Bởi vì một phép nối bên trong được sử dụng, kết quả sẽ chỉ hiển thị các hàng đã được nối. Vì truy vấn sử dụng ký tự đại diện *
, tất cả các cột từ cả hai bảng sẽ được hiển thị.
Điều này có nghĩa là cả id
cột từ table1
và ident
cột từ table2
sẽ được hiển thị, mặc dù chúng có cùng giá trị chính xác do thỏa mãn điều kiện kết hợp. Bạn có thể tránh sự trùng lặp này bằng cách gọi ra các cột chính xác mà bạn muốn hiển thị trong SELECT
danh sách cột.
USING
mệnh đề
USING
mệnh đề là cách viết tắt để chỉ định các điều kiện của ON
mệnh đề có thể được sử dụng khi các cột được so sánh có cùng tên trong cả hai bảng. USING
mệnh đề có một danh sách, đặt trong dấu ngoặc đơn, các tên cột được chia sẻ sẽ được so sánh.
Cú pháp chung của USING
mệnh đề sử dụng định dạng này:
SELECT *FROM table1JOIN table2USING (id, state);
Sự kết hợp này kết hợp table1
với table2
khi hai cột mà cả hai bảng chia sẻ (id
và state
) đều có các giá trị phù hợp.
Sự liên kết tương tự này có thể được diễn đạt chi tiết hơn bằng cách sử dụng ON
như thế này:
SELECT *FROM table1JOIN table2ON table1.id = table2.id AND table1.state = table2.state;
Mặc dù cả hai phép nối ở trên sẽ dẫn đến việc các hàng giống nhau được tạo với cùng một dữ liệu hiện tại, chúng sẽ được hiển thị hơi khác nhau. Trong khi ON
mệnh đề bao gồm tất cả các cột từ cả hai bảng, USING
mệnh đề ngăn chặn các cột trùng lặp. Vì vậy, thay vì có hai id
riêng biệt cột và hai state
riêng biệt (một cho mỗi bảng), kết quả sẽ chỉ có một trong mỗi cột được chia sẻ, theo sau là tất cả các cột khác được cung cấp bởi table1
và table2
.
NATURAL
mệnh đề
NATURAL
mệnh đề là một cách viết tắt khác có thể làm giảm thêm tính dài dòng của USING
mệnh đề. A NATURAL
tham gia không chỉ định bất kỳ các cột được so khớp. Thay vào đó, PostgreSQL sẽ tự động nối các bảng dựa trên tất cả các cột có các cột phù hợp trong mỗi cơ sở dữ liệu.
Cú pháp chung của NATURAL
mệnh đề tham gia có dạng như sau:
SELECT *FROM table1NATURAL JOIN table2;
Giả sử rằng table1
và table2
cả hai đều có các cột có tên id
, state
và company
, truy vấn trên sẽ tương đương với truy vấn này bằng cách sử dụng ON
mệnh đề:
SELECT *FROM table1JOIN table2ON table1.id = table2.id AND table1.state = table2.state AND table1.company = table2.company;
Và truy vấn này bằng cách sử dụng USING
mệnh đề:
SELECT *FROM table1JOIN table2USING (id, state, company);
Giống như USING
mệnh đề NATURAL
mệnh đề loại bỏ các cột trùng lặp, vì vậy sẽ chỉ có một trường hợp duy nhất của mỗi cột được kết hợp trong kết quả.
Trong khi NATURAL
mệnh đề có thể làm giảm tính dài dòng của các truy vấn của bạn, bạn phải cẩn thận khi sử dụng nó. Bởi vì các cột được sử dụng để nối các bảng được tính toán tự động, nếu các cột trong bảng thành phần thay đổi, kết quả có thể rất khác nhau do các điều kiện nối mới.
Tham gia điều kiện và WHERE
mệnh đề
Các điều kiện tham gia chia sẻ nhiều đặc điểm với các so sánh được sử dụng để lọc các hàng dữ liệu bằng cách sử dụng WHERE
điều khoản. Cả hai cấu trúc đều xác định các biểu thức phải đánh giá là đúng đối với hàng được xem xét. Do đó, không phải lúc nào cũng trực quan sự khác biệt giữa việc bao gồm các so sánh bổ sung trong một WHERE
xây dựng so với xác định chúng trong chính mệnh đề tham gia.
Để hiểu được sự khác biệt sẽ dẫn đến, chúng ta phải xem xét thứ tự mà PostgreSQL xử lý các phần khác nhau của một truy vấn. Trong trường hợp này, các vị từ trong điều kiện nối được xử lý đầu tiên để xây dựng bảng liên kết ảo trong bộ nhớ. Sau giai đoạn này, các biểu thức trong WHERE
mệnh đề được đánh giá để lọc các hàng kết quả.
Ví dụ:giả sử rằng chúng ta có hai bảng được gọi là customer
và order
mà chúng ta cần tham gia cùng nhau. Chúng tôi muốn kết hợp hai bảng bằng cách đối sánh customer.id
với order.customer_id
cột. Ngoài ra, chúng tôi quan tâm đến các hàng trong order
bảng có product_id
trong tổng số 12345.
Với những yêu cầu trên, chúng ta có hai điều kiện cần quan tâm. Tuy nhiên, cách chúng tôi thể hiện những điều kiện này sẽ quyết định kết quả chúng tôi nhận được.
Đầu tiên, hãy sử dụng cả hai làm điều kiện tham gia cho một LEFT JOIN
:
SELECT customer.id AS customer_id, customer.name, order.id AS order_id, order.product_idFROM customerLEFT JOIN orderON customer.id = order.customer_id AND order.product_id = 12345;
Kết quả có thể trông giống như sau:
customer_id | name | order_id | product_id ------------+----------+----------+------------ 4380 | Acme Co | 480 | 12345 4380 | Acme Co | 182 | 12345 320 | Other Co | 680 | 12345 4380 | Acme Co | | 320 | Other Co | | 20 | Early Co | | 8033 | Big Co | |(7 rows)
PostgreSQL đạt được kết quả này bằng cách thực hiện các thao tác sau:
- Kết hợp bất kỳ hàng nào trong
customer
bảng vớiorder
bảng trong đó:-
customer.id
khớp vớiorder.customer_id
. -
order.product_id
phù hợp với 12345
-
- Bởi vì chúng tôi đang sử dụng kết hợp bên trái, hãy bao gồm mọi thứ chưa kết hợp hàng từ bảng bên trái (
customer
), đệm các cột từ bảng bên phải (order
) vớiNULL
giá trị. - Chỉ hiển thị các cột được liệt kê trong
SELECT
đặc điểm kỹ thuật của cột.
Kết quả là tất cả các hàng đã tham gia của chúng tôi phù hợp với cả hai điều kiện mà chúng tôi đang tìm kiếm. Tuy nhiên, phép nối bên trái khiến PostgreSQL cũng bao gồm bất kỳ hàng nào từ bảng đầu tiên không thỏa mãn điều kiện nối. Điều này dẫn đến các hàng "còn lại" dường như không tuân theo ý định rõ ràng của truy vấn.
Nếu chúng ta di chuyển truy vấn thứ hai (order.product_id
=12345) đến một WHERE
, thay vì bao gồm nó như một điều kiện kết hợp, chúng tôi nhận được các kết quả khác nhau:
SELECT customer.id AS customer_id, customer.name, order.id AS order_id, order.product_idFROM customerLEFT JOIN orderON customer.id = order.customer_idWHERE order.product_id = 12345;
Lần này, chỉ có ba hàng được hiển thị:
customer_id | name | order_id | product_id ------------+----------+----------+------------ 4380 | Acme Co | 480 | 12345 4380 | Acme Co | 182 | 12345 320 | Other Co | 680 | 12345(3 rows)
Thứ tự thực hiện các phép so sánh là lý do cho những khác biệt này. Lần này, PostgreSQL xử lý truy vấn như sau:
- Kết hợp bất kỳ hàng nào trong
customer
bảng vớiorder
bảng trong đócustomer.id
khớp vớiorder.customer_id
. - Bởi vì chúng tôi đang sử dụng kết hợp bên trái, hãy bao gồm mọi thứ chưa kết hợp hàng từ bảng bên trái (
customer
), đệm các cột từ bảng bên phải (order
) vớiNULL
giá trị. - Đánh giá
WHERE
mệnh đề xóa bất kỳ hàng nào không có 12345 làm giá trị choorder.product_id
cột. - Chỉ hiển thị các cột được liệt kê trong
SELECT
đặc điểm kỹ thuật của cột.
Lần này, mặc dù chúng tôi đang sử dụng kết hợp bên trái, WHERE
mệnh đề cắt bớt kết quả bằng cách lọc ra tất cả các hàng không có product_id
chính xác . Bởi vì bất kỳ hàng nào chưa khớp sẽ có product_id
đặt thành NULL
, điều này sẽ xóa tất cả các hàng chưa khớp đã được điền bởi phép nối bên trái. Nó cũng xóa bất kỳ hàng nào được khớp với điều kiện kết hợp không vượt qua vòng kiểm tra thứ hai này.
Hiểu được quy trình cơ bản mà PostgreSQL sử dụng để thực thi các truy vấn của bạn có thể giúp bạn tránh một số lỗi dễ mắc phải nhưng khó gỡ lỗi khi bạn làm việc với dữ liệu của mình.
Kết luận
Trong hướng dẫn này, chúng tôi đã đề cập đến cách các phép nối cho phép cơ sở dữ liệu quan hệ kết hợp dữ liệu từ các bảng khác nhau để cung cấp các câu trả lời có giá trị hơn. Chúng ta đã nói về các liên kết khác nhau mà PostgreSQL hỗ trợ, cách mỗi loại kết hợp các kết quả của nó và những gì sẽ xảy ra khi sử dụng các loại liên kết cụ thể. Sau đó, chúng tôi đã xem xét các cách khác nhau để xác định các điều kiện kết hợp và xem xét cách thức tác động qua lại giữa các phép nối và WHERE
mệnh đề có thể dẫn đến bất ngờ.
Tham gia là một phần thiết yếu làm cho cơ sở dữ liệu quan hệ đủ mạnh mẽ và linh hoạt để xử lý rất nhiều loại truy vấn khác nhau. Tổ chức dữ liệu bằng cách sử dụng các ranh giới hợp lý trong khi vẫn có thể kết hợp lại dữ liệu theo những cách mới trong từng trường hợp cụ thể mang lại cho cơ sở dữ liệu quan hệ như PostgreSQL tính linh hoạt đáng kinh ngạc. Học cách thực hiện việc ghép nối này giữa các bảng sẽ cho phép bạn tạo các truy vấn phức tạp hơn và dựa vào cơ sở dữ liệu để tạo ra các bức tranh hoàn chỉnh về dữ liệu của bạn.