Oracle
 sql >> база данни >  >> RDS >> Oracle

Използването на IS NULL или IS NOT NULL при условия на присъединяване - Теоретичен въпрос

Пример с таблици A и 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  

Ако искате да намерите родители и техните деца, направете INNER JOIN :

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

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

Резултатът е, че всяко съвпадение на родител id на от лявата таблица и дете pid от втората таблица ще се покаже като ред в резултата:

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

Сега горното не показва родители без деца (тъй като техните идентификационни номера нямат съвпадение в идентификаторите на детето, така че какво правите? Вместо това правите външно присъединяване. Има три вида външни свързвания, ляво, дясно и пълното външно присъединяване. Трябва ни лявото, тъй като искаме "допълнителните" редове от лявата таблица (родител):

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

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

Резултатът е, че освен предишни мачове, всички родители, които нямат съвпадение (прочетете:нямат дете) също се показват:

+----+--------+------+-------+
| 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 идвам от? Е, MySQL (или всяка друга RDBMS, която може да използвате) няма да знае какво да постави там, тъй като тези родители нямат съвпадение (дете), така че няма pid нито child.name да съвпадат с тези родители. И така, той поставя тази специална нестойност, наречена NULL .

Моето мнение е, че тези NULL се създават (в резултатния набор) по време на LEFT OUTER JOIN .

Така че, ако искаме да покажем само родителите, които НЯМАТ дете, можем да добавим WHERE child.pid IS NULL към LEFT JOIN по-горе. КЪДЕ Клаузата се оценява (проверява) след JOIN готово е. Така че от горния резултат е ясно, че само последните три реда, където pid е NULL ще се покаже:

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

Резултат:

+----+--------+------+-------+
| id | parent | pid  | child | 
+----+--------+------+-------+
|  2 | Bill   | NULL | NULL  |
|  4 | Dale   | NULL | NULL  |
|  5 | Evan   | NULL | NULL  |
+----+--------+------+-------+

Сега, какво ще стане, ако преместим това IS NULL проверете от КЪДЕ към присъединителния 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

В този случай базата данни се опитва да намери редове от двете таблици, които отговарят на тези условия. Тоест редове, където parent.id =child.pid И child.pid В NULL . Но може да намери няма такова съвпадение защото няма child.pid може да бъде равно на нещо (1, 2, 3, 4 или 5) и да бъде NULL в същото време!

И така, условието:

ON   parent.id    =    child.pid
AND  child.pid IS NULL

е еквивалентен на:

ON   1 = 0

което винаги е False .

И така, защо връща ВСИЧКИ редове от лявата таблица? Защото е ЛЯВО ПРИСЪЕДИНЯВАНЕ! И левите съединения връщат редове, които съвпадат (в този случай няма) а също иредове от лявата таблица, които не съвпадати проверката (всички в този случай ):

+----+--------+------+-------+
| id | parent | pid  | child | 
+----+--------+------+-------+
|  1 | Alex   | NULL | NULL  |
|  2 | Bill   | NULL | NULL  |
|  3 | Cath   | NULL | NULL  |
|  4 | Dale   | NULL | NULL  |
|  5 | Evan   | NULL | NULL  |
+----+--------+------+-------+

Надявам се, че горното обяснение е ясно.

Странична бележка (не е пряко свързана с вашия въпрос):Защо, за бога, не Pan не се показват в нито едно от нашите JOIN? Защото неговият pid е NULL и NULL в (не обичайната) логика на SQL не е равно на нищо, така че не може да съвпадне с нито един от родителските идентификатори (които са 1,2,3,4 и 5). Дори и да имаше NULL там, то пак нямаше да съвпадне, защото NULL не е равно на нищо, дори не на NULL (това е много странна логика, наистина!). Ето защо използваме специалната проверка IS NULL а не =NULL проверете.

Така че, ще Панорамиране се появяват, ако направим RIGHT JOIN ? Да, ще стане! Тъй като RIGHT JOIN ще покаже всички резултати, които съвпадат (първото INNER JOIN, което направихме) плюс всички редове от ДЯСНАТА таблица, които не съвпадат (което в нашия случай е един, (NULL, 'Pan') ред.

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

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

Резултат:

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

За съжаление MySQL няма FULL JOIN . Можете да го опитате в други RDBMS и той ще покаже:

+------+--------+------+-------+
|  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. Заявка за проверка на размера на таблицата в базата данни на Oracle

  2. какъв jdbc jar да използвате с oracle 11g &jdk 1.6 и как да се свържете със самия db

  3. как да променя съществуващо ограничение за проверка?

  4. Тип таблица в Пример за съхранявана процедура на Oracle

  5. Създайте файл на Excel (.xlsx) с помощта на PL/SQL