Ví dụ với bảng A và B:
A (parent) B (child)
============ =============
id | name pid | name
------------ -------------
1 | Alex 1 | Kate
2 | Bill 1 | Lia
3 | Cath 3 | Mary
4 | Dale NULL | Pan
5 | Evan
Nếu bạn muốn tìm cha mẹ và con cái họ, bạn làm một INNER JOIN
: Kết quả
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent INNER JOIN child
ON parent.id = child.pid
là mỗi trận đấu của một từ bảng bên trái và child
's pid
từ bảng thứ hai sẽ hiển thị dưới dạng hàng trong kết quả:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
+----+--------+------+-------+
Bây giờ, ở trên không cho thấy các bậc cha mẹ mà không trẻ em (vì id của họ không có một trận đấu trong id của con, vì vậy bạn sẽ làm gì? Thay vào đó bạn thực hiện một phép nối ngoài. Có ba loại tham gia bên ngoài, bên trái, bên phải và bên ngoài tham gia đầy đủ. Chúng ta cần một trái như chúng ta muốn "thêm" hàng từ bảng bên trái (mẹ):
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent LEFT JOIN child
ON parent.id = child.pid
Kết quả là bên cạnh các trận đấu trước đó, tất cả các bậc cha mẹ mà không có một trận đấu (đọc: không có đứa trẻ) cũng được hiển thị:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
| 2 | Bill | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Trường hợp tất cả những gì NULL
đến từ đâu? Vâng, MySQL (hoặc bất kỳ RDBMS nào khác mà bạn có thể sử dụng) sẽ không biết phải đặt gì ở đây vì những bậc cha mẹ này không khớp với nhau, vì vậy không có pid
cũng không phải child.name
để phù hợp với những bậc cha mẹ đó. Vì vậy, nó đặt giá trị không đặc biệt này được gọi là NULL
.
Điểm của tôi là NULLs
này được tạo (trong tập kết quả) trong LEFT OUTER JOIN
.
Vì vậy, nếu chúng ta muốn hiển thị chỉ các bậc phụ huynh KHÔNG có một đứa trẻ, chúng ta có thể thêm một WHERE child.pid IS NULL
đến LEFT JOIN
trên. Điều khoản WHERE
được đánh giá (đã chọn) sau khi thực hiện xong JOIN
.Vì vậy, nó là rõ ràng từ kết quả trên mà chỉ có ba hàng cuối cùng nơi pid
là NULL sẽ được hiển thị:
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent LEFT JOIN child
ON parent.id = child.pid
WHERE child.pid IS NULL
Kết quả:
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 2 | Bill | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Bây giờ, những gì sẽ xảy ra nếu chúng ta di chuyển mà IS NULL
kiểm tra từ WHERE
để tham gia khoản ON
?
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent LEFT JOIN child
ON parent.id = child.pid
AND child.pid IS NULL
Trong trường hợp này, cơ sở dữ liệu tìm các hàng từ hai bảng phù hợp với các điều kiện này. Tức là, các hàng nơi parent.id = child.pid
VÀchild.pid IN NULL
. Nhưng nó có thể tìm thấy không có kết quả như vậy vì không có child.pid
có thể bằng một cái gì đó (1, 2, 3, 4 hoặc 5) và là NULL cùng một lúc!
Vì vậy, điều kiện:
ON parent.id = child.pid
AND child.pid IS NULL
tương đương với:
ON 1 = 0
mà luôn luôn là False
.
Vì vậy, tại sao nó trả về TẤT CẢ các hàng từ bảng bên trái? Bởi vì nó là một LEFT JOIN! Và trái tham gia trở lại hàng phù hợp (không có trong trường hợp này) và cũng hàng từ bảng bên trái mà không phù hợp kiểm tra (tất cả trong trường hợp này):
+----+--------+------+-------+
| id | parent | pid | child |
+----+--------+------+-------+
| 1 | Alex | NULL | NULL |
| 2 | Bill | NULL | NULL |
| 3 | Cath | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
+----+--------+------+-------+
Tôi hy vọng lời giải thích ở trên là rõ ràng.
Sidenote (không liên quan trực tiếp đến câu hỏi của bạn): Tại sao trên trái đất không Pan
hiển thị trong không ai trong số JOIN của chúng tôi? Bởi vì pid
của mình là NULL
và NULL trong (không phổ biến) logic của SQL là không bằng bất cứ điều gì vì vậy nó không thể phù hợp với bất kỳ id cha mẹ (mà là 1,2,3,4 và 5). Ngay cả khi có một NULL ở đó, nó vẫn sẽ không phù hợp bởi vì NULL
không bằng bất cứ điều gì, thậm chí không NULL
chính nó (đó là một logic rất lạ, thực sự!). Đó là lý do chúng tôi sử dụng séc đặc biệt IS NULL
và không phải séc = NULL
.
Vì vậy, sẽ Pan
hiển thị nếu chúng tôi thực hiện RIGHT JOIN
? Nó sẽ được thôi! Bởi vì một RIGHT JOIN sẽ hiển thị tất cả kết quả trận đấu đó (INNER đầu tiên THAM GIA chúng tôi đã làm) cộng với tất cả các hàng từ bảng QUYỀN mà không phù hợp (mà trong trường hợp của chúng ta là một, hàng (NULL, 'Pan')
.
SELECT id, parent.name AS parent
, pid, child.name AS child
FROM
parent RIGHT JOIN child
ON parent.id = child.pid
quả :
+------+--------+------+-------+
| id | parent | pid | child |
+---------------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
| NULL | NULL | NULL | Pan |
+------+--------+------+-------+
Thật không may, MySQL không có FULL JOIN
.Bạn có thể thử nó trong RDBMS khác, và nó sẽ hiển thị:
+------+--------+------+-------+
| id | parent | pid | child |
+------+--------+------+-------+
| 1 | Alex | 1 | Kate |
| 1 | Alex | 1 | Lia |
| 3 | Cath | 3 | Mary |
| 2 | Bill | NULL | NULL |
| 4 | Dale | NULL | NULL |
| 5 | Evan | NULL | NULL |
| NULL | NULL | NULL | Pan |
+------+--------+------+-------+
Bạn có thể giả mạo 'FULL JOIN' trong MySQL bằng cách lấy liên kết giữa' LEFT JOIN' và 'RIGHT JOIN' trong đó id là' NULL'. Điều này có những hạn chế - ví dụ, bạn không thể cập nhật hoặc xóa - và có lẽ là rắc rối nhiều hơn nó có giá trị. – Duncan