Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Sử dụng IS NULL hoặc IS NOT NULL với các điều kiện tham gia - Câu hỏi lý thuyết

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 của họ, bạn thực hiện INNER JOIN :

SELECT id,  parent.name AS parent
     , pid, child.name  AS child

FROM
        parent  INNER JOIN  child
  ON   parent.id     =    child.pid

Kết quả là mọi kết quả trùng khớp của parent id của từ bảng bên trái và một child của pid từ bảng thứ hai sẽ hiển thị dưới dạng một 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ờ, phần trên không hiển thị các bậc cha mẹ không có con (vì id của họ không khớp với id của trẻ, vậy bạn phải làm gì? liên kết bên ngoài đầy đủ. Chúng tôi cần liên kết bên trái vì chúng tôi muốn các hàng "bổ sung" từ bảng bên trái (chính):

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 phụ huynh không có trận đấu (đọc:không có con) 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  |
+----+--------+------+-------+

Tất cả những NULL đó ở đâu đến từ? Chà, 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ì ở đó vì những phụ huynh này không có đối sánh (con), vì vậy không có pid cũng không phải child.name để phù hợp với các bậc cha mẹ đó. Vì vậy, nó đặt giá trị không đặc biệt này được gọi là NULL .

Ý của tôi là những NULL này được tạo (trong tập kết quả) trong LEFT OUTER JOIN .

Vì vậy, nếu chúng ta chỉ muốn hiển thị những bậc cha mẹ KHÔNG có con, chúng ta có thể thêm WHERE child.pid IS NULL vào LEFT JOIN bên trên. WHERE mệnh đề được đánh giá (kiểm tra) sau JOIN đã xong. Vì vậy, rõ ràng từ kết quả trên, chỉ có ba hàng cuối cùng mà 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ờ, điều gì sẽ xảy ra nếu chúng ta di chuyển IS NULL đó kiểm tra từ WHERE tham gia ON mệnh đề?

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 cố gắng tìm các hàng từ hai bảng phù hợp với các điều kiện này. Đó là, các hàng mà parent.id = child.pid child.pid IN NULL . Nhưng nó có thể tìm thấy không có kết quả phù hợp nào 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à đồng thời là NULL!

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

cái nào luôn False .

Vì vậy, tại sao nó trả về TẤT CẢ các hàng từ bảng bên trái? Vì đó là THAM GIA TRÁI! Và các phép nối bên trái trả về hàng phù hợp (không có hàng nào trong trường hợp này) và cả các hàng từ bảng bên trái không khớp séc ( 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.

Chú thích phụ (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 không xuất hiện trong các THAM GIA của chúng tôi? Bởi vì pid của anh ấy là NULL và NULL trong logic (không phổ biến) của SQL không bằng bất kỳ thứ gì nên nó không thể khớp với bất kỳ id mẹ nào (là 1,2,3,4 và 5). Ngay cả khi có NULL ở đó, nó vẫn không khớp vì NULL không bằng bất cứ thứ gì, thậm chí không bằng NULL chính nó (đó là một logic rất kỳ lạ, thực sự!). Đó là lý do tại sao chúng tôi sử dụng kiểm tra đặc biệt IS NULL và không phải là = NULL kiểm tra.

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ì THAM GIA PHẢI sẽ hiển thị tất cả các kết quả khớp (THAM GIA BÊN TRONG đầu tiên mà chúng tôi đã thực hiện) cộng với tất cả các hàng từ bảng RIGHT không khớp (trong trường hợp của chúng tôi là một, (NULL, 'Pan') hàng.

SELECT id,  parent.name AS parent
     , pid, child.name  AS child

FROM
        parent  RIGHT JOIN  child
  ON   parent.id     =    child.pid

Kết quả:

+------+--------+------+-------+
| id   | parent | pid  | child | 
+---------------+------+-------+
|   1  | Alex   |   1  | Kate  |
|   1  | Alex   |   1  | Lia   |
|   3  | Cath   |   3  | Mary  |
| NULL | NULL   | NULL | Pan   |
+------+--------+------+-------+

Rất tiếc, MySQL không có FULL JOIN . Bạn có thể thử nó trong các 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   |
+------+--------+------+-------+


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách tạo PL / SQL SYS_REFCURSOR trong cơ sở dữ liệu Oracle

  2. Chia chuỗi theo khoảng trắng và ký tự làm dấu phân cách trong Oracle với regexp_substr

  3. cx_Oracle và Xử lý ngoại lệ - Các phương pháp hay?

  4. Cách định dạng số bằng dấu trừ / dấu cộng trong Oracle

  5. Sắp xếp theo ngày trong tuần từ thứ 2 đến chủ nhật