SQL JOIN
là gì và các loại khác nhau là gì?
SQL JOIN
là gì và các loại khác nhau là gì?
Câu trả lời:
SQL JOIN
gìSQL JOIN
là một phương thức để lấy dữ liệu từ hai hoặc nhiều bảng cơ sở dữ liệu.
SQL JOIN
s khác nhau là gì?Có tổng cộng năm JOIN
s. Họ đang :
1. JOIN or INNER JOIN
2. OUTER JOIN
2.1 LEFT OUTER JOIN or LEFT JOIN
2.2 RIGHT OUTER JOIN or RIGHT JOIN
2.3 FULL OUTER JOIN or FULL JOIN
3. NATURAL JOIN
4. CROSS JOIN
5. SELF JOIN
Trong loại này JOIN
, chúng tôi nhận được tất cả các bản ghi khớp với điều kiện trong cả hai bảng và các bản ghi trong cả hai bảng không khớp đều không được báo cáo.
Nói cách khác, INNER JOIN
dựa trên một thực tế duy nhất là: CHỈ các mục phù hợp trong CẢ HAI các bảng NÊN được liệt kê.
Lưu ý rằng một JOIN
mà không cần bất kỳ khác JOIN
từ khóa (như INNER
, OUTER
, LEFT
, vv) là một INNER JOIN
. Nói cách khác, JOIN
là một đường cú pháp cho INNER JOIN
(xem: Sự khác biệt giữa THAM GIA và THAM GIA VÀO ).
OUTER JOIN
lấy
Hoặc, các hàng được khớp từ một bảng và tất cả các hàng trong bảng khác Hoặc, tất cả các hàng trong tất cả các bảng (không quan trọng có khớp hay không).
Có ba loại Tham gia ngoài:
2.1 LEFT OUTER THAM GIA hoặc TRÁI THAM GIA
Phép nối này trả về tất cả các hàng từ bảng bên trái kết hợp với các hàng khớp từ bảng bên phải. Nếu không có cột nào khớp trong bảng bên phải, nó sẽ trả về NULL
giá trị.
2.2 RIGHT OUTER THAM GIA hoặc RIGHT THAM GIA
Điều này JOIN
trả về tất cả các hàng từ bảng bên phải kết hợp với các hàng phù hợp từ bảng bên trái. Nếu không có cột nào khớp trong bảng bên trái, nó sẽ trả về NULL
giá trị.
2.3 FULL OUTER THAM GIA hoặc FULL THAM GIA
Điều này JOIN
kết hợp LEFT OUTER JOIN
và RIGHT OUTER JOIN
. Nó trả về các hàng từ một trong hai bảng khi các điều kiện được đáp ứng và trả về NULL
giá trị khi không có kết quả khớp.
Nói cách khác, OUTER JOIN
dựa trên thực tế rằng: CHỈ các mục phù hợp trong MỘT TRONG các bảng (ĐÚNG hoặc TRÁI) hoặc CẢ HAI bảng (ĐẦY ĐỦ) NÊN được liệt kê.
Note that `OUTER JOIN` is a loosened form of `INNER JOIN`.
Nó dựa trên hai điều kiện:
JOIN
được thực hiện trên tất cả các cột có cùng tên cho bình đẳng.Điều này có vẻ mang tính lý thuyết nhiều hơn và do đó, có lẽ (hầu hết) DBMS thậm chí không bận tâm đến việc hỗ trợ này.
Đây là sản phẩm của Cartesian trong hai bảng liên quan. Kết quả của một CROSS JOIN
ý chí sẽ không có ý nghĩa trong hầu hết các tình huống. Hơn nữa, chúng tôi sẽ không cần điều này cả (hoặc cần ít nhất, chính xác).
Nó không phải là một hình thức khác nhau của JOIN
, chứ không phải nó là một JOIN
( INNER
, OUTER
, vv) của một bảng với chính nó.
Tùy thuộc vào toán tử được sử dụng cho một JOIN
mệnh đề, có thể có hai loại JOIN
s. họ đang
Đối với bất kỳ JOIN
loại nào ( INNER
,, OUTER
v.v.), nếu chúng ta chỉ sử dụng toán tử đẳng thức (=), thì chúng ta nói rằng đó JOIN
là một EQUI JOIN
.
Điều này giống như EQUI JOIN
nhưng nó cho phép tất cả các toán tử khác như>, <,> = vv
Nhiều người coi cả hai
EQUI JOIN
và ThetaJOIN
tương tựINNER
,OUTER
vvJOIN
s. Nhưng tôi tin tưởng mạnh mẽ rằng đó là một sai lầm và làm cho các ý tưởng trở nên mơ hồ. Bởi vìINNER JOIN
,OUTER JOIN
v.v ... tất cả đều được kết nối với các bảng và dữ liệu của chúng trong khiEQUI JOIN
vàTHETA JOIN
chỉ được kết nối với các toán tử mà chúng ta sử dụng trước đây.Một lần nữa, có nhiều người coi đó
NATURAL JOIN
là một loại "kỳ dị"EQUI JOIN
. Trong thực tế, đó là sự thật, vì điều kiện đầu tiên tôi đề cập đếnNATURAL JOIN
. Tuy nhiên, chúng tôi không phải hạn chế chỉ đơn giảnNATURAL JOIN
là một mình.INNER JOIN
s,OUTER JOIN
s vv có thể là mộtEQUI JOIN
quá.
Định nghĩa:
THAM GIA là cách để truy vấn dữ liệu kết hợp cùng một lúc từ nhiều bảng.
Mối quan tâm đến RDBMS có 5 loại liên kết:
Equi-Join: Kết hợp các bản ghi chung từ hai bảng dựa trên điều kiện bình đẳng. Về mặt kỹ thuật, Tham gia được thực hiện bằng cách sử dụng toán tử đẳng thức (=) để so sánh các giá trị của Khóa chính của một bảng và các giá trị Khóa ngoài của một bảng khác, do đó tập kết quả bao gồm các bản ghi chung (khớp) từ cả hai bảng. Để thực hiện, xem INNER-THAM GIA.
Tham gia tự nhiên: Đây là phiên bản nâng cao của Equi-Join, trong đó thao tác CHỌN bỏ qua cột trùng lặp. Để thực hiện, xem INNER-THAM GIA
Không tham gia Equi-Join: Nó ngược lại với Equi-jo trong đó điều kiện tham gia được sử dụng khác với toán tử bằng (=), ví dụ: =, <=,> =,>, <hoặc GIỮA, v.v. Để thực hiện, hãy xem INNER-THAM GIA.
Tự tham gia :: Một hành vi tùy chỉnh tham gia trong đó một bảng kết hợp với chính nó; Điều này thường là cần thiết để truy vấn các bảng tự tham chiếu (hoặc thực thể mối quan hệ Unary). Để thực hiện, xem INNER-THAM GIA.
Sản phẩm Cartesian: Nó kết hợp chéo tất cả các bản ghi của cả hai bảng mà không có bất kỳ điều kiện. Về mặt kỹ thuật, nó trả về tập kết quả của một truy vấn mà không có WHERE-Article.
Theo sự quan tâm và tiến bộ của SQL, có 3 loại liên kết và tất cả các phép nối RDBMS có thể đạt được bằng cách sử dụng các loại liên kết này.
INNER-THAM GIA: Nó hợp nhất (hoặc kết hợp) các hàng khớp từ hai bảng. Việc khớp được thực hiện dựa trên các cột chung của bảng và hoạt động so sánh của chúng. Nếu điều kiện dựa trên sự bình đẳng thì: Đã thực hiện THIẾT BỊ-THAM GIA, nếu không thì không tham gia.
OUTER-THAM GIA: Nó kết hợp (hoặc kết hợp) hàng xuất từ hai bảng và các hàng chưa từng có với các giá trị NULL. Tuy nhiên, có thể tùy chỉnh lựa chọn các hàng không khớp, ví dụ: chọn hàng chưa khớp từ bảng đầu tiên hoặc bảng thứ hai theo loại phụ: LEFT OUTER THAM GIA và RIGHT OUTER THAM GIA.
2.1. LEFT Outer THAM GIA (còn gọi là LEFT-THAM GIA): Chỉ trả về các hàng khớp từ hai bảng và không khớp với bảng LEFT (tức là bảng đầu tiên).
2.2. RIGHT Outer THAM GIA (hay còn gọi là RIGHT-THAM GIA): Trả về các hàng khớp từ hai bảng và không khớp với chỉ bảng RIGHT.
2.3. FULL OUTER THAM GIA (còn gọi là OUTER THAM GIA): Trả về khớp và không khớp từ cả hai bảng.
CROSS-THAM GIA: Sự tham gia này không hợp nhất / kết hợp thay vào đó nó thực hiện sản phẩm của Cartesian.
Lưu ý: Tự THAM GIA có thể đạt được bằng INNER-THAM GIA, NGOÀI-THAM GIA và CROSS-THAM GIA dựa trên yêu cầu nhưng bảng phải tham gia với chính nó.
1.1: INNER-THAM GIA: Thực hiện Equi-tham gia
SELECT *
FROM Table1 A
INNER JOIN Table2 B ON A.<Primary-Key> =B.<Foreign-Key>;
1.2: INNER-THAM GIA: Thực hiện tự nhiên-THAM GIA
Select A.*, B.Col1, B.Col2 --But no B.ForeignKeyColumn in Select
FROM Table1 A
INNER JOIN Table2 B On A.Pk = B.Fk;
1.3: INNER-THAM GIA với triển khai NON-Equi-tham gia
Select *
FROM Table1 A INNER JOIN Table2 B On A.Pk <= B.Fk;
1.4: THAM GIA-THAM GIA với TỰ TIN
Select *
FROM Table1 A1 INNER JOIN Table1 A2 On A1.Pk = A2.Fk;
2.1: OUTER THAM GIA (tham gia đầy đủ bên ngoài)
Select *
FROM Table1 A FULL OUTER JOIN Table2 B On A.Pk = B.Fk;
2.2: THAM GIA
Select *
FROM Table1 A LEFT OUTER JOIN Table2 B On A.Pk = B.Fk;
2.3: THAM GIA QUYỀN
Select *
FROM Table1 A RIGHT OUTER JOIN Table2 B On A.Pk = B.Fk;
3.1: THAM GIA CROSS
Select *
FROM TableA CROSS JOIN TableB;
3.2: THAM GIA CROSS-Tự tham gia
Select *
FROM Table1 A1 CROSS JOIN Table1 A2;
//HOẶC LÀ//
Select *
FROM Table1 A1,Table1 A2;
intersect
/ except
/ union
; ở đây các vòng tròn là các hàng được trả về bởi left
& right
join
, như các nhãn được đánh số. Hình ảnh AXB là vô nghĩa. cross join
= inner join on 1=1
& là trường hợp đặc biệt của sơ đồ đầu tiên.
UNION JOIN
. Bây giờ đã lỗi thời trong SQL: 2003.
Điều thú vị là hầu hết các câu trả lời khác đều gặp phải hai vấn đề này:
Gần đây tôi đã viết một bài viết về chủ đề: Hướng dẫn toàn diện, có thể chưa hoàn chỉnh về nhiều cách khác nhau để tham gia các bảng trong SQL , mà tôi sẽ tóm tắt ở đây.
Đây là lý do tại sao các sơ đồ Venn giải thích chúng không chính xác, bởi vì THAM GIA tạo ra một sản phẩm cartesian giữa hai bảng được nối. Wikipedia minh họa nó độc đáo:
Cú pháp SQL cho các sản phẩm cartesian là CROSS JOIN
. Ví dụ:
SELECT *
-- This just generates all the days in January 2017
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Here, we're combining all days with all departments
CROSS JOIN departments
Kết hợp tất cả các hàng từ một bảng với tất cả các hàng từ bảng khác:
Nguồn:
+--------+ +------------+
| day | | department |
+--------+ +------------+
| Jan 01 | | Dept 1 |
| Jan 02 | | Dept 2 |
| ... | | Dept 3 |
| Jan 30 | +------------+
| Jan 31 |
+--------+
Kết quả:
+--------+------------+
| day | department |
+--------+------------+
| Jan 01 | Dept 1 |
| Jan 01 | Dept 2 |
| Jan 01 | Dept 3 |
| Jan 02 | Dept 1 |
| Jan 02 | Dept 2 |
| Jan 02 | Dept 3 |
| ... | ... |
| Jan 31 | Dept 1 |
| Jan 31 | Dept 2 |
| Jan 31 | Dept 3 |
+--------+------------+
Nếu chúng ta chỉ viết một danh sách các bảng được phân tách bằng dấu phẩy, chúng ta sẽ nhận được cùng một:
-- CROSS JOINing two tables:
SELECT * FROM table1, table2
An INNER JOIN
chỉ là một CROSS JOIN
bộ lọc trong đó vị từ bộ lọc được gọi Theta
trong đại số quan hệ.
Ví dụ:
SELECT *
-- Same as before
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Now, exclude all days/departments combinations for
-- days before the department was created
JOIN departments AS d ON day >= d.created_at
Lưu ý rằng từ khóa INNER
là tùy chọn (ngoại trừ trong MS Access).
( nhìn vào bài báo cho ví dụ kết quả )
Một loại Theta-THAM GIA đặc biệt là Equi THAM GIA, mà chúng tôi sử dụng nhiều nhất. Vị ngữ kết hợp khóa chính của một bảng với khóa ngoại của bảng khác. Nếu chúng ta sử dụng cơ sở dữ liệu Sakila để minh họa, chúng ta có thể viết:
SELECT *
FROM actor AS a
JOIN film_actor AS fa ON a.actor_id = fa.actor_id
JOIN film AS f ON f.film_id = fa.film_id
Điều này kết hợp tất cả các diễn viên với bộ phim của họ.
Hoặc cũng có thể, trên một số cơ sở dữ liệu:
SELECT *
FROM actor
JOIN film_actor USING (actor_id)
JOIN film USING (film_id)
Các USING()
cú pháp cho phép xác định một cột đó phải có mặt ở hai bên của lệnh JOIN bảng hoạt động và tạo ra một vị bình đẳng trên hai cột.
Các câu trả lời khác đã liệt kê riêng loại "THAM GIA" này, nhưng điều đó không có ý nghĩa. Đây chỉ là một dạng cú pháp cho Equi THAM GIA, đây là trường hợp đặc biệt của Theta-THAM GIA hoặc INNER THAM GIA. NATURAL THAM GIA chỉ đơn giản là thu thập tất cả các cột chung cho cả hai bảng được nối và nối USING()
các cột đó. Điều này hầu như không bao giờ hữu ích, vì các kết LAST_UPDATE
quả trùng khớp ngẫu nhiên (như các cột trong cơ sở dữ liệu Sakila ).
Đây là cú pháp:
SELECT *
FROM actor
NATURAL JOIN film_actor
NATURAL JOIN film
Bây giờ, OUTER JOIN
có một chút khác biệt so INNER JOIN
với khi nó tạo ra một UNION
số sản phẩm cartesian. Chúng tôi có thể viết:
-- Convenient syntax:
SELECT *
FROM a LEFT JOIN b ON <predicate>
-- Cumbersome, equivalent syntax:
SELECT a.*, b.*
FROM a JOIN b ON <predicate>
UNION ALL
SELECT a.*, NULL, NULL, ..., NULL
FROM a
WHERE NOT EXISTS (
SELECT * FROM b WHERE <predicate>
)
Không ai muốn viết cái sau, vì vậy chúng tôi viết OUTER JOIN
(thường được tối ưu hóa tốt hơn bởi cơ sở dữ liệu).
Giống như INNER
, từ khóa OUTER
là tùy chọn, ở đây.
OUTER JOIN
có ba hương vị:
LEFT [ OUTER ] JOIN
: Bảng bên trái của JOIN
biểu thức được thêm vào liên minh như được hiển thị ở trên.RIGHT [ OUTER ] JOIN
: Bảng bên phải của JOIN
biểu thức được thêm vào liên minh như được hiển thị ở trên.FULL [ OUTER ] JOIN
: Cả hai bảng của JOIN
biểu thức được thêm vào liên minh như được hiển thị ở trên.Tất cả những thứ này có thể được kết hợp với từ khóa USING()
hoặc với NATURAL
( Tôi thực sự đã có một trường hợp sử dụng trong thế giới thực NATURAL FULL JOIN
gần đây )
Có một số cú pháp lịch sử, không dùng nữa trong Oracle và SQL Server, đã được hỗ trợ OUTER JOIN
trước khi tiêu chuẩn SQL có cú pháp cho việc này:
-- Oracle
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)
-- SQL Server
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id *= fa.actor_id
AND fa.film_id *= f.film_id
Đã nói như vậy, không sử dụng cú pháp này. Tôi chỉ liệt kê điều này ở đây để bạn có thể nhận ra nó từ các bài đăng blog cũ / mã kế thừa.
OUTER JOIN
Ít người biết điều này, nhưng tiêu chuẩn SQL chỉ định phân vùng OUTER JOIN
(và Oracle thực hiện nó). Bạn có thể viết những thứ như thế này:
WITH
-- Using CONNECT BY to generate all dates in January
days(day) AS (
SELECT DATE '2017-01-01' + LEVEL - 1
FROM dual
CONNECT BY LEVEL <= 31
),
-- Our departments
departments(department, created_at) AS (
SELECT 'Dept 1', DATE '2017-01-10' FROM dual UNION ALL
SELECT 'Dept 2', DATE '2017-01-11' FROM dual UNION ALL
SELECT 'Dept 3', DATE '2017-01-12' FROM dual UNION ALL
SELECT 'Dept 4', DATE '2017-04-01' FROM dual UNION ALL
SELECT 'Dept 5', DATE '2017-04-02' FROM dual
)
SELECT *
FROM days
LEFT JOIN departments
PARTITION BY (department) -- This is where the magic happens
ON day >= created_at
Các phần của kết quả:
+--------+------------+------------+
| day | department | created_at |
+--------+------------+------------+
| Jan 01 | Dept 1 | | -- Didn't match, but still get row
| Jan 02 | Dept 1 | | -- Didn't match, but still get row
| ... | Dept 1 | | -- Didn't match, but still get row
| Jan 09 | Dept 1 | | -- Didn't match, but still get row
| Jan 10 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 11 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 12 | Dept 1 | Jan 10 | -- Matches, so get join result
| ... | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 31 | Dept 1 | Jan 10 | -- Matches, so get join result
Vấn đề ở đây là tất cả các hàng từ phía được phân vùng của phép nối sẽ kết thúc trong kết quả bất kể có JOIN
khớp với bất cứ thứ gì ở "phía bên kia của THAM GIA" hay không. Câu chuyện dài: Đây là để điền vào dữ liệu thưa thớt trong các báo cáo. Rất hữu ích!
Nghiêm túc? Không có câu trả lời khác có điều này? Tất nhiên là không, vì nó không có cú pháp riêng trong SQL, thật không may (giống như ANTI THAM GIA bên dưới). Nhưng chúng ta có thể sử dụng IN()
và EXISTS()
, ví dụ để tìm tất cả các diễn viên đã đóng trong các bộ phim:
SELECT *
FROM actor a
WHERE EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
Vị WHERE a.actor_id = fa.actor_id
ngữ đóng vai trò là vị ngữ bán tham gia. Nếu bạn không tin, hãy xem kế hoạch thực hiện, ví dụ như trong Oracle. Bạn sẽ thấy rằng cơ sở dữ liệu thực hiện một hoạt động SEMI THAM GIA, không phải là EXISTS()
vị ngữ.
Đây mới chỉ là đối diện của BÁN JOIN ( cẩn thận không để sử dụng NOT IN
mặc dù , vì nó có một caveat quan trọng)
Dưới đây là tất cả các diễn viên không có phim:
SELECT *
FROM actor a
WHERE NOT EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
Một số người (đặc biệt là người MySQL) cũng viết ANTI THAM GIA như thế này:
SELECT *
FROM actor a
LEFT JOIN film_actor fa
USING (actor_id)
WHERE film_id IS NULL
Tôi nghĩ lý do lịch sử là hiệu suất.
OMG, cái này quá tuyệt Tôi là người duy nhất đề cập đến nó? Đây là một truy vấn thú vị:
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
LEFT OUTER JOIN LATERAL (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa USING (film_id)
JOIN inventory AS i USING (film_id)
JOIN rental AS r USING (inventory_id)
JOIN payment AS p USING (rental_id)
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
ON true
Nó sẽ tìm thấy TOP 5 doanh thu sản xuất phim cho mỗi diễn viên. Mỗi khi bạn cần một truy vấn TOP-N-per-Something, LATERAL JOIN
sẽ là bạn của bạn. Nếu bạn là người của SQL Server, thì bạn biết JOIN
loại này dưới tênAPPLY
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
OUTER APPLY (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa ON f.film_id = fa.film_id
JOIN inventory AS i ON f.film_id = i.film_id
JOIN rental AS r ON i.inventory_id = r.inventory_id
JOIN payment AS p ON r.rental_id = p.rental_id
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
OK, có lẽ đó là gian lận, bởi vì một LATERAL JOIN
hoặc APPLY
biểu thức thực sự là một "truy vấn con tương quan" tạo ra một số hàng. Nhưng nếu chúng ta cho phép "truy vấn con tương quan", chúng ta cũng có thể nói về ...
Điều này chỉ thực sự được thực hiện bởi Oracle và Informix (theo hiểu biết của tôi), nhưng nó có thể được mô phỏng trong PostgreQuery bằng cách sử dụng mảng và / hoặc XML và trong SQL Server bằng XML.
MULTISET
tạo ra một truy vấn con tương quan và lồng tập hợp các hàng kết quả trong truy vấn bên ngoài. Truy vấn dưới đây chọn tất cả các diễn viên và cho mỗi diễn viên thu thập các bộ phim của họ trong một bộ sưu tập lồng nhau:
SELECT a.*, MULTISET (
SELECT f.*
FROM film AS f
JOIN film_actor AS fa USING (film_id)
WHERE a.actor_id = fa.actor_id
) AS films
FROM actor
Như bạn đã thấy, có rất nhiều loại THAM GIA hơn chỉ là "nhàm chán" INNER
, OUTER
và CROSS JOIN
rằng thường đề cập. Thêm chi tiết trong bài viết của tôi . Và xin vui lòng, ngừng sử dụng biểu đồ Venn để minh họa chúng.
Tôi sẽ đẩy peeve thú cưng của tôi: từ khóa SỬ DỤNG.
Nếu cả hai bảng ở cả hai phía của THAM GIA đều có khóa ngoại được đặt tên chính xác (nghĩa là cùng tên, không chỉ "id) thì có thể sử dụng bảng này:
SELECT ...
FROM customers JOIN orders USING (customer_id)
Tôi thấy điều này rất thực tế, dễ đọc và không được sử dụng thường xuyên.