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

НЕ В селекция с NULL стойности

Първо малко теория:Null (SQL)

Най-важните части за нас от горната връзка:

Сравнения с NULL и тризначната логика (3VL)

Тъй като Null не е член на нито един домейн на данни, той не се счита за "стойност", а по-скоро за маркер (или заместител), указващ отсъствието на стойност. Поради това сравненията с Null никога не могат да доведат нито до вярно, нито до грешно, а винаги до трети логически резултат, неизвестен.[8] Логическият резултат от израза по-долу, който сравнява стойността 10 с Null, е Неизвестен:

SELECT 10 = NULL       -- Results in Unknown

така че и двете сравнения:x = NULL и x <> NULL оценява на NULL (неизвестно).

SQL реализира три логически резултата, така че SQL реализациите трябва да осигуряват специализирана тризначна логика (3VL). Правилата, управляващи тризначната логика на SQL, са показани в таблиците по-долу (p иq представляват логически състояния)"[9] Таблиците на истинността, които SQL използва за И, ИЛИ и НЕ съответстват на общ фрагмент от тризначната логика на Kleene и Łukasiewicz ( които се различават по своята дефиниция на импликация, но SQL не дефинира такава операция).

+---------+-------------+-------------+-------------+-----------+--------+
|    p    |        q    |     p OR q  |     p AND q |    p = q  |p != q  |
+---------+-------------+-------------+-------------+-----------+--------+
| True    |     True    |     True    |     True    |   True    | False  |
| True    |     False   |     True    |     False   |   False   | True   |
| True    |     Unknown |     True    |     Unknown |   Unknown | Unknown|
| False   |     True    |     True    |     False   |   False   | True   |
| False   |     False   |     False   |     False   |   True    | False  |
| False   |     Unknown |     Unknown |     False   |   Unknown | Unknown|
| Unknown |     True    |     True    |     Unknown |   Unknown | Unknown|
| Unknown |     False   |     Unknown |     False   |   Unknown | Unknown|
| Unknown |     Unknown |     Unknown |     Unknown |   Unknown | Unknown|
+---------+-------------+-------------+-------------+-----------+--------+

Ефект на неизвестно в клаузите WHERE

SQL тризначна логика се среща в езика за манипулиране на данни (DML) в предикатите за сравнение на DML изрази и заявки. Клаузата WHERE кара DML оператора да действа само върху онези редове, за които предикатът оценява на True.

Така накратко:клаузата WHERE третира NULL като FALSE

Сега, моля, помислете за по-прост случай:

SELECT * FROM T1;

|      X |
|--------|
|      1 |
| (null) |

и заявка:

SELECT * FROM t1 WHERE x IN (1, NULL);

Горната заявка е кратка за тази:

SELECT * FROM t1 
WHERE x = 1
  OR  x = NULL

За втория ред от таблица t ( x =NULL) това условие изглежда така:

WHERE NULL = 1
   OR NULL = NULL

така че това условие за реда x=NULL оценява на NULL, защото NULL=1 е NULL, NULL=NULL е NULL и NULL OR NULL също е NULL (моля, вижте таблицата 3VL по-горе).

Сега помислете за по-любопитен случай:

SELECT * FROM t1 WHERE x NOT IN (1, NULL);

Тази клауза x NOT IN (1, NULL) е еквивалентен на NOT ( x IN (1, NULL) )
така че също е еквивалентен на:

NOT (
  x = 1
  OR
  x = NULL
)

и според законите на Де Морган е еквивалентен на:

NOT ( x = 1 ) AND NOT ( x = NULL )

и (ако заменим NOT x = y с x <> y ) също е еквивалентен на:

 x <> 1 AND x <> NULL

Моля, разгледайте внимателно последното условие:

WHERE 
x <> 1 AND x <> NULL

Знаем от x <> NULL винаги се оценява на NULL. Също така знаем от таблицата 3VL по-горе, че и двете true AND NULL е NULL и false AND NULL оценява на FALSE, така че цялото условие винаги се оценява на FALSE или NULL, но никога не се оценява на TRUE.

Следователно заявка с това условие:

SELECT .....
WHERE x NOT IN ( NULL, whatever)

винаги връща празен набор от резултати

И сега вашата заявка, която също е любопитна:

SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);

който може да бъде пренаписан (използвайки константни стойности) на:

SELECT * FROM t1
WHERE (id, val) NOT IN (
       (1, null),
       (2, 2 )
)

Тази заявка използва така наречения израз за стойност на ред

По принцип условие, използващо изразената стойност на реда като този

(a, b) = (x, y)

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

a = x AND b = y

така че горната заявка може да бъде пренаписана в тази:

SELECT * FROM t1
WHERE NOT (
   id = 1 AND val = NULL
   OR
   id = 2 AND val = 2
)

Според законите на Де Морган това е идентично на:

SELECT * FROM t1
WHERE 
   NOT ( id = 1 AND val = NULL )
   AND
   NOT ( id = 2 AND val = 2 )

и по-нататък:

SELECT * FROM t1
WHERE 
   ( id <> 1 OR val <> NULL )
   AND
   ( id <> 2 OR val <> 2 )

От първата част ( id <> 1 OR val <> NULL ) на условието се оценява на вярно само в случай, когато id <> 1 (моля, вижте таблицата 3VL по-горе), това условие може да бъде опростено до:

SELECT * FROM t1
WHERE 
   ( id <> 1 )
   AND
   ( id <> 2 OR val <> 2 )

и по-нататък (според законите на Де Морган) в:

SELECT * FROM t1
WHERE 
   id <> 1 AND id <> 2
   OR
   id <> 1 AND  val <> 2

така че нито (1,1) нито (2,2) от изходния data1 спазват тези условия.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как мога да получа изходен параметър на съхранената процедура, който е масив, който да работи?

  2. Как да показвате по-ясно данните от таблицата в oracle sqlplus

  3. oracle SQL плюс как да прекратя командата в SQL файл?

  4. Oracle получава стойност на контролната сума за блок от данни, дефиниран от клауза за избор

  5. Oracle ORA-01008:не всички променливи са обвързани Грешка с параметри