Чому NULL = NULL оцінює значення false на SQL-сервері


146

На сервері SQL, якщо у вас є nullParam=NULLпункт де, він завжди оцінюється як хибний. Це контрінтуїтивно і спричинило у мене багато помилок. Я розумію, IS NULLі IS NOT NULLключові слова - це правильний спосіб зробити це. Але чому SQL-сервер поводиться так?


166
У мене немає сестри, а також немає мого друга. Якщо "NULL = NULL", то у нас є спільна сестра, і тому пов'язані! :)
Метт Гамільтон

11
Існує тривала суперечка щодо SQL NULL (див. Наприклад: en.wikipedia.org/wiki/Null_%28SQL%29#Controversy та firstsql.com/inulls.htm ). Конкретний момент полягає в тому, що рівність - це давно усталене математичне поняття, і SQL порушує його - рівність є рефлексивною: для кожного x, x = x. Це має бути завжди правдою, інакше вводити тлумачення рівності, яке не є стандартним, а плутанина - очевидний результат.
MaD70

14
Це зовсім не порушує математику. Я думаю про два числа. Я не збираюся розповідати вам, що вони є. Тож тепер ви мені скажіть, чи рівні вони?
Том Н

10
@Matt, я не згоден з вашою аналогією. NULL = NULL не означає, що у вас є спільна сестра, це означатиме, що вам обом не вистачає сестри.
reustmd

5
@ manu08 Ні, поточна реалізація (що NULL ніколи не дорівнює NULL) означає, що нам обом не вистачає сестри, що було моїм бажанням.
Метт Гамільтон

Відповіді:


205

Подумайте про нуль як "невідомий" у тому випадку (або "не існує"). В жодному з цих випадків ви не можете сказати, що вони рівні, тому що ви не знаєте значення жодного з них. Отже, null = null оцінюється як неправда (false або null, залежно від вашої системи), оскільки ви не знаєте значень, щоб сказати, що вони рівні. Така поведінка визначена в стандарті ANSI SQL-92.

EDIT: Це залежить від налаштувань ansi_nulls . якщо у вас ANSI_NULLS вимкнено, це буде ВІДПОВІДНО. Запустіть наступний код для прикладу ...

set ansi_nulls off

if null = null
    print 'true'
else
    print 'false'


set ansi_nulls ON

if null = null
    print 'true'
else
    print 'false'

11
x = x справедливо лише тоді, коли x є відомим значенням. NULL - це текстове зображення невідомого значення. Якщо у вас є два невідомих значення, ви не можете остаточно сказати нічого про їх рівність. Я вважаю, що це також було правдою протягом кількох століть.
Девейн Крістенсен

4
Оскільки грудень - грудень, давайте скористаємося сезонним прикладом. У мене є два подарунки під деревом. А тепер ти мені скажи, чи дістали я дві однакові речі чи ні.
Девейн Крістенсен

5
SQL NULL нічим не відрізняється від IEEE з плаваючою точкою NaN, де ви також є (NaN == NaN) == false && (NaN != Nan) == false && (NaN < NaN) == false && ...- бо, ну, якщо це не число, ви просто не можете сказати багато про це; це щось невідоме. Концепція є здоровою, навіть якщо вона не інтуїтивна для людей, які її ніколи раніше не бачили.
Павло Мінаєв

8
Тут немає порушення рефлексивності, оскільки NULL не є членом набору значень (домен, у реляційному відношенні). NULL не є значенням . Це заповнювач невідомого значення.
Павло Мінаєв

9
Іншими словами, кожен NULLу виразі SQL може трактуватися як окрема математична змінна. Отже, вираз NULL = NULLслід трактувати як x = y, де xі yє незв'язаними змінними. Тепер, якщо хтось запитує у вас, яка цінність x = y? Єдина розумна відповідь - "деякі z". Таким чином , у нас є (x = y) = z- або, транскрибувати його назад в SQL, (NULL = NULL) = NULL.
Павло Мінаєв

130

Скільки років Френку? Я не знаю (null).

Скільки років Ширлі? Я не знаю (null).

Френк і Ширлі одного віку?

Правильна відповідь повинна бути "я не знаю" (нульовий), а не "ні", оскільки Френк і Ширлі можуть бути одного віку, ми просто не знаємо.


4
Я не погоджуюся, що null означає "невідомо". Що насправді означає "немає даних". Це може бути використане для представлення випадків, коли інформація не відома, але насправді більш імовірно використовуватиметься для вказівки на те, що щось не існує. Щоб продовжити ваш приклад: Яке прізвище Франка? У нього немає (null). Яке ім'я Ширлі? У неї немає (null). Чи мають Френк і Ширлі одне середнє ім’я? Так? Немає? Не знаєте? Я бачу аргумент "ні", і я бачу аргумент "не знаю", але немає реального аргументу "так", якщо ви не надто буквальні.
Річібан

2
@richiban Я не згоден. Відсутність рядка означає «немає даних»
Ніл Макгуйган

1
@NeilMcGuigan Це правда, якщо для даних, які мають свою власну таблицю, але що з даними, представленими у стовпці? Чи не використовуєте ви "null", щоб представити факт відсутності даних? "Невідомо" - це дуже конкретна причина відсутності даних.
Річібан

3
Але null = nullврожайність FALSE, ні NULL.
slartidan

1
@slartidan Я згоден з вами, однак це неправильно
Ніл

28

Тут я сподіваюся прояснити свою позицію.

Це NULL = NULLобчислюватися FALSEнеправильно. Хакер і Містер правильно відповіли NULL. Ось чому. Девейн Крістенсен написав мені в коментарі до Скотта Айві :

Оскільки грудень - грудень, давайте скористаємося сезонним прикладом. У мене є два подарунки під деревом. А тепер ти мені скажи, чи дістали я дві однакові речі чи ні.

Вони можуть бути різними або вони можуть бути рівними, ви не знаєте, поки один не відкриє обидва подарунка. Хто знає? Ви запросили двох людей, які не знають один одного, і обидва зробили вам один і той же подарунок - рідкісний, але не неможливий § .

Тож питання: чи є ці два НЕЗНАЧЕНІ однакові (рівні, =)? Правильна відповідь: НЕВІДОМО (тобто NULL).

Цей приклад мав на меті продемонструвати, що ".. ( falseабо null, залежно від вашої системи) .." - це правильна відповідь - це не так, лише NULL правильна в 3VL (чи нормально для вас прийняти систему, яка дає неправильні відповіді? )

Правильна відповідь на це питання повинна підкреслювати ці два моменти:

  • тризначна логіка (3VL) є протиінтуїтивною (див. незліченну кількість питань з цього приводу на Stackoverflow та на інших форумах);
  • На основі SQL СУБД часто не поважають навіть 3VL, вони іноді дають неправильні відповіді (як, наприклад, оригінальне затвердження плакатів, SQL Server у цьому випадку).

Тому я повторюю: SQL не дуже добре змушує інтерпретувати рефлексивну властивість рівності, яка стверджує, що:

for any x, x = x §§ (простою англійською мовою: незалежно від всесвіту дискурсу, "річ" завжди дорівнює самому собі ).

.. в 3VL ( TRUE, FALSE, NULL). Очікування людей відповідатиме 2VL ( TRUE, FALSEщо навіть у SQL справедливо для всіх інших значень), тобто x = x завжди оцінювати до TRUE будь-якого можливого значення x - не виняток.

Зауважте також, що NULL є дійсними " не-значеннями " (як вважають їх апологети), які можна призначити як значення атрибутів (??) як частина змінних відношень. Тож вони є прийнятними значеннями кожного типу (домену), а не лише типу логічних виразів.

І в цьому була моя думка : NULLяк цінність - «дивний звір». Без евфемізму я вважаю за краще: дурниці .

Я думаю, що ця формулювання набагато чіткіше і менш дискусійне - вибачте за моє слабке знання англійської мови.

Це лише одна з проблем NULL. Краще уникати їх цілком, коли це можливо.

§ ми стурбовані цінностями , тому той факт, що два подарунки - це завжди два різні фізичні об'єкти, не є дійсним запереченням; якщо ви не впевнені, вибачте, це не місце пояснити різницю між значеннями та "об'єктною" семантикою (реляційна алгебра має значення значення семантики з самого початку - див. інформаційний принцип Кодда; я думаю, що деякі реалізатори SQL СУБД роблять Навіть не піклується про загальну семантику).

§§ наскільки мені відомо, це аксіома, прийнята (у тій чи іншій формі, але завжди інтерпретована у 2ВЛ) ще з античності, і саме тому, що настільки інтуїтивно зрозуміла. 3VL (насправді сімейство логіків) є набагато пізнішою розробкою (але я не впевнений, коли вперше був розроблений).

Побічна примітка: якщо хтось буде представляти типи Bottom , Unit та Option як спроби виправдати SQL NULL, я переконаюсь лише після досить детального вивчення, яке покаже, як реалізація SQL з NULLs має систему звукового типу, і, нарешті, уточнить, що насправді є NULL (ці "не зовсім цінні значення").


У подальшому я цитую деяких авторів. Будь-яка помилка чи упущення, ймовірно, є моїм, а не оригінальним авторам.

Джо Селко на SQL NULL

Я бачу, як Джо Селко часто цитується на цьому форумі. Мабуть, він тут дуже шановний автор. Отже, я сказав собі: "що він пише про SQL NULL? Як він пояснює численні проблеми NULL?". Один мій друг має електронну версію SQL Джо Селко для розумних розробок: розширене програмування SQL, 3-е видання . Подивимось.

По-перше, зміст. Найбільше мене вражає, скільки разів згадується NULL та в найрізноманітніших контекстах:

3.4 Арифметичні та NULLs 109
3.5 Перетворення значень в та з NULL 110
3.5.1 Функція NULLIF () 110
6 NULL: відсутні дані в SQL 185
6.4 Порівняння NULLs 190
6.5 NULLs та Logic 190
6.5.1 NULLS в предикатах предикатів 191
6.5.2 Стандарт Рішення SQL 193
6.6 Математика та NULLs 193
6.7 Функції та NULLs 193
6.8 NULLs та мови хостів 194
6.9 Консультації з дизайну для NULLs 195
6.9.1 Уникання NULL з хост-програм 197
6.10 Примітка про кілька значень NULL 198
10.1 IS NULL Predicate 241
10.1. 1 Джерела NULLs 242
...

і так далі. Мені дзвонить "бридкий особливий випадок" для мене.

Я розберуся в деяких із цих випадків із уривками з цієї книги, намагаючись обмежитися істотними з міркувань авторського права. Я думаю, що ці цитати належать до доктрини "добросовісного використання", і вони навіть можуть стимулювати придбання книги - тому сподіваюся, що ніхто не скаржиться (інакше мені потрібно буде видалити більшу частину, якщо не все). Крім того, я утримаюсь від звітних фрагментів коду з тієї ж причини. Вибач за це. Купіть книгу, щоб прочитати про деталізовані міркування.

Наступні номери сторінок між дужками.

НЕ NULL обмеження (11)

Найважливішим обмеженням стовпця є NOT NULL, який забороняє використовувати NULLs у ​​стовпці. Використовуйте це обмеження звичайно, і усувайте його лише тоді, коли у вас є вагомі причини. Це допоможе вам уникнути ускладнень значень NULL, коли ви робите запити щодо даних.

Це не цінність ; це маркер, який займає місце, куди може йти значення.

Знову ця дурниця "цінність, але не зовсім цінність". Решта мені здається досить розумною.

(12)

Коротше кажучи, NULL викликає багато нерегулярних функцій у SQL, про які ми підемо пізніше. Ваша найкраща ставка - це просто запам'ятати ситуації та правила для NULL, коли ви не можете їх уникнути.

Пропозиції SQL, NULL і нескінченного:

(104) РОЗДІЛ 3: Числові дані в SQL

SQL не прийняв модель IEEE для математики з кількох причин.

...

Якщо правила IEEE для математики були дозволені в SQL, то нам знадобляться правила перетворення типу для нескінченності та спосіб представити нескінченне точне числове значення після перетворення. У людей достатньо проблем з NULL, тому не будемо туди йти.

Реалізації SQL не визначилися з тим, що насправді означає NULL у конкретних контекстах:

3.6.2 Експоненціальні функції (116)

Проблема полягає в тому, що логарифми не визначені, коли (x <= 0). Деякі реалізації SQL повертають повідомлення про помилку, деякі повертають NULL та DB2 / 400; версія 3 випуску 1 повертається * NEGINF (скорочення "негативна нескінченність") як результат.

Джо Челко, цитуючи Девіда МакГоверана та CJ Date:

6 NULL: відсутні дані в SQL (185)

У своїй книзі «Керівництво по Sybase та SQL Server» Девід МакГоверан та CJ Date зазначили: «Це думка цього автора, ніж NULL, принаймні, як це визначено та впроваджено в SQL, - набагато більше проблем, ніж їх варто та їх слід уникати; вони проявляють дуже дивну та непослідовну поведінку і можуть бути багатим джерелом помилок та плутанини. (Зверніть увагу, що ці коментарі та зауваження стосуються будь-якої системи, яка підтримує NULL-стилі у стилі SQL, а не лише до SQL Server.) "

NULL як наркоманія :

(186/187)

В решті цієї книги я закликаю вас не користуватися ними , що може здатися суперечливим, але це не так. Подумайте про НІЛЛ як наркотик; використовуйте його належним чином, і він працює для вас, але зловживайте ним, і це може зіпсувати все. Ваша найкраща політика - уникати NULL, коли ви можете та правильно їх використовувати, коли потрібно.

Моє унікальне заперечення тут - "використовувати їх належним чином", що погано взаємодіє з конкретними способами поведінки.

6.5.1 NULLS в предикатах підзапиту (191/192)

Люди забувають, що підзапит часто приховує порівняння з NULL. Розглянемо ці дві таблиці:

...

Результат буде порожнім. Це контрінтуїтивно , але правильно.

(роздільник)

6.5.2 Стандартні рішення SQL (193)

SQL-92 вирішив деякі проблеми 3VL (тризначна логіка), додавши новий предикат форми:

<умова пошуку> Є [НЕ] ІСТИНА | ПОМИЛКА | НЕЗНАЧЕНО

Але НЕВІДОМЛЕННЕ є самим джерелом проблем, так що CJ Date, у своїй цитованій нижче книзі, рекомендує голову 4.5. Уникнення нулів у SQL :

  • Не використовуйте ключове слово UNKNOWN ні в якому контексті.

Прочитайте "ДОПОМОГА" в невідомому , також пов'язаному нижче.

6.8 NULL та мови господарів (194)

Однак ви повинні знати, як обробляються NULL, коли вони повинні бути передані хост-програмі. Жодна стандартна мова хоста, для якої визначено вбудовування, не підтримує NULL, що є ще однією вагомою причиною уникати використання їх у схемі бази даних.

(роздільник)

6.9 Консультації з дизайну для NULL (195)

Добре задекларувати всі свої базові таблиці з обмеженнями NULL на всіх стовпцях, коли можливо. NULL плутають людей, які не знають SQL, а NULL - це дорого.

Заперечення: NULL збиває з пантелику навіть людей, які добре знають SQL, див. Нижче.

(195)

У ІНОЗЕМНИХ КЛЮЧАХ слід уникати NULL. SQL дозволяє це співвідношення «користь сумніву», але це може призвести до втрати інформації в запитах, що передбачають приєднання. Наприклад, враховуючи код номера деталі в Інвентарі, на який посилається як ІНТЕРНЕТ-КЛЮЧ таблицею замовлень, у вас виникнуть проблеми з переліком частин, які мають NULL. Це обов'язкові відносини; ви не можете замовити частину, яка не існує.

(роздільник)

6.9.1 Уникнення NULL з хост-програм (197)

Ви можете уникнути введення NULL в базу даних з програм Хост з деякою дисципліною програмування.

...

  1. Визначте вплив відсутніх даних на програмування та звітування: Числові стовпці з NULL є проблемою, оскільки запити, що використовують сукупні функції, можуть дати оманливі результати.

(роздільник)

(227)

SUM () порожнього набору завжди NULL. Однією з найпоширеніших помилок програмування, допущеною при використанні цього фокусу, є написання запиту, який може повернути більше одного рядка. Якщо ви не замислювалися над цим, ви, можливо, написали останній приклад як: ...

(роздільник)

10.1.1 Джерела NULL (242)

Важливо пам’ятати, де можуть виникати NULL. Вони є більш ніж просто можливим значенням у стовпці . Функції сукупності на порожніх множинах, OUTER JOINs, арифметичні вирази з NULL і оператори OLAP повертають NULL. Ці конструкції часто відображаються у вигляді стовпців у VIEW.

(роздільник)

(301)

Інша проблема з NULL виявляється при спробі перетворення предикатів IN у предикати EXISTS.

(роздільник)

16.3 ВСІ функції предиката та екстремуму (313)

Спочатку протипоказано, що ці два предикати не однакові в SQL:

...

Але ви повинні пам'ятати правила для екстремальних функцій - вони викидають усі NULL, перш ніж повертати великі або найменші значення. ВСЕ предикат не скидає NULL, тому ви можете отримати їх у результатах.

(роздільник)

(315)

Однак визначення в стандарті сформульовано негативно, так що NULL отримають користь від сумніву. ...

Як бачите, добре уникати NULLs в УНІКАЛЬНИХ обмеженнях.

Обговорення групи за:

NULL трактуються так, ніби всі вони рівні між собою , і утворюють свою власну групу. Потім кожна група зменшується до одного рядка в новій таблиці результатів, яка замінює стару.

Це означає, що для GROUP BY пункт NULL = NULL не оцінюється як NULL, як у 3VL, але оцінює до TRUE.

Стандарт SQL заплутано:

ЗАМОВЛЕННЯ ПО ТА НУЛЬ (329)

Будь-яке ключове значення сортування, яке NULL, вважається більшим або меншим за значення, яке не є NULL, визначається реалізацією, але ...

... Є продукти SQL, які роблять це в будь-якому випадку.

У березні 1999 року Кріс Фаррар поставив запитання у одного з його розробників, яке змусило його вивчити частину стандарту SQL, яку я вважав зрозумілою . Кріс виявив деякі відмінності між загальним розумінням та фактичним формулюванням специфікації .

І так далі. Я думаю, що це досить.

Дата CJ для NQL з SQL

Дата CJ є більш радикальною щодо NULL: уникайте NULL в SQL, період. Насправді, глава 4 його SQL та реляційної теорії: Як правильно писати код SQL має назву "НЕ ДУПЛІКАЦІЙ, НІ НУЛЛІВ", з підрозділами "4.4 Що не так з нулями?" та "4.5 Уникнення нулів у SQL" (перейдіть за посиланням: завдяки Google Книгам ви можете читати деякі сторінки в режимі он-лайн).

Фабіан Паскаль на SQL NULL

З його практичних питань управління базами даних - довідник для практикуючого мислення (немає витягів онлайн, вибачте):

10.3 Пратичні наслідки

10.3.1 SQL NULL

... SQL страждає від проблем, властивих 3VL, а також від багатьох химерностей, ускладнень, контрінтуїтивності та відвертих помилок [10, 11]; серед них такі:

  • Функції сукупності (наприклад, SUM (), AVG ()) ігнорують NULL (крім COUNT ()).
  • Скалярний вираз на таблиці без рядків оцінюється неправильно NULL, замість 0.
  • Вираз "NULL = NULL" оцінюється як NULL, але насправді є недійсним у SQL; але ORDER BY трактує NULL як рівні (що б вони не передували або виконували "регулярні" значення залишається постачальнику СУБД).
  • Вираз "x НЕ NULL" не дорівнює "NOT (x IS NULL)", як це стосується 2VL.

...

Усі діалектні SQL, комерційно реалізовані, дотримуються цього підходу 3VL, і, таким чином, вони не лише виявляють ці проблеми, але і мають специфічні проблеми з реалізацією, які залежать від продуктів .


4
"І це був мій погляд: NULL, як цінність, є" дивним звіром "." - це тому NULL, що не є цінністю.
Павло Мінаєв

1
Також SQL Server не дає (NULL = NULL) -> FALSE. Процитуйте документацію для ANSI_NULLS: "Коли вказано значення ВКЛ, всі порівняння з нульовим значенням оцінюються НЕВІДОМЛЕНО . Коли ВИМКНЕНО визначено, порівняння не UNICODE значень з нульовим значенням оцінюється на ІСТИНА, якщо обидва значення NULL".
Павло Мінаєв

@Pavel Мінаєв: а) і наскільки ІСТИНА краща за ЛЖУ? б) Якщо це не значення, чому воно призначається як частина змінних значень?
MaD70

1
>> Оскільки грудень - грудень, давайте скористаємося сезонним прикладом. У мене є два подарунки під деревом. А тепер ти мені скажи, чи дістали я дві однакові речі чи ні. ... так, ви зробили так, як у вас дві речі, і , наскільки ви зараз стурбовані , в міру ваших теперішніх знань, вони вам точно такі самі
Бред Томас

3
null = null має бути правдою. нуль коректно визначено значення , яке може представляти собою невідоме значення, але воно може також представляти в відсутність числа. Розробник повинен вирішувати, що означає null, але саме null - це абсолютно значення, а null - null = null. Будь-яка інша реалізація пов'язана з катастрофами, оскільки ви втручаєте потрійну логіку в предикати, які є принципово булевими. Я ВДОМУВАТЬ, що це стає постійним у налаштуваннях на SQL-сервері. ВИМКНЕНО ВИКЛ.
Трайнко


9

Тільки те, що ви не знаєте, що таке дві речі, не означає, що вони рівні. Якщо ви думаєте про те, що NULLви думаєте про "NULL" (рядок), то, ймовірно, ви хочете іншого тесту на рівність, як Postgresql's IS DISTINCT FROMANDIS NOT DISTINCT FROM

З документів PostgreSQL на тему "Функції порівняння та оператори"

вираз IS DISTINCT FROMвираз

вираз IS NOT DISTINCT FROMвираз

Для ненульових входів - IS DISTINCT FROMце те саме, що і <>оператор. Однак, якщо обидва введення є недійсними, він повертає помилкове значення, а якщо лише один вхід є нульовим, він повертає істинне. Аналогічно, IS NOT DISTINCT FROMвін ідентичний =для ненульових входів, але він повертає істину, коли обидва введення є нульовими, а помилковими, коли лише один вхід є нульовим. Таким чином, ці конструкції ефективно діють так, ніби нульові значення були нормальним, а не "невідомим".


5

Поняття NULL є, щонайменше, сумнівним. Кодд представив реляційну модель і концепцію NULL в контексті (і запропонував запропонувати більше одного типу NULL!) Однак реляційна теорія розвинулася з моменту оригінальних творів Кодда: деякі його пропозиції відтоді були відкинуті (наприклад, первинний ключ) та інші, які ніколи не потрапляють (наприклад, оператори тети). У сучасній реляційній теорії (справді реляційної теорії, я повинен наголосити) NULL просто не існує. Дивіться Третій маніфест. http://www.thethirdmanifesto.com/

Мова SQL страждає від проблеми зворотної сумісності. NULL знайшов свій шлях у SQL, і ми з цим застрягли. Можливо, реалізація NULLв SQL є хибною (реалізація SQL Server робить речі ще складнішими через його ANSI_NULLSможливості).

Я рекомендую уникати використання стовпців NULLable у базових таблицях.


Хоча, можливо, я не повинен спокушатися, я просто хотів стверджувати власні корективи про те, як NULLпрацює в SQL:

NULL= NULLоцінює до UNKNOWN.

UNKNOWN є логічним значенням.

NULL - це значення даних.

Це легко довести, наприклад

SELECT NULL = NULL

правильно генерує помилку в SQL Server. Якби результатом було значення даних, ми б очікували побачити NULL, як деякі відповіді тут (неправильно) підказують, що ми б.

Логічне значення UNKNOWNтрактується по-різному в SQL DML і SQL DDL відповідно.

У SQL DML UNKNOWNвикликає видалення рядків із набору результатів.

Наприклад:

CREATE TABLE MyTable
(
 key_col INTEGER NOT NULL UNIQUE, 
 data_col INTEGER
 CHECK (data_col = 55)
);

INSERT INTO MyTable (key_col, data_col)
   VALUES (1, NULL);

Успіх INSERTдля цього ряду, навіть якщо ця CHECKумова дозволена NULL = NULL. Це обумовлено стандартом SQL-92 ("ANSI"):

11.6 визначення обмежень таблиці

3)

Якщо обмеження таблиці є визначенням обмеження для перевірки, то нехай SC - умова пошуку негайно, що міститься у визначенні обмеження перевірки, і нехай T - ім'я таблиці, включене у відповідний дескриптор обмеження таблиці; обмеження таблиці не виконується, якщо і лише тоді

ІСНУЄ (ВИБІР * З ТОГО, де НЕ (SC))

правда.

Прочитайте це ще раз уважно, дотримуючись логіки.

Простий англійською мовою наш новий рядок вище надається "користю сумнівів" щодо того, що перебуває UNKNOWNта може пройти.

У SQL DML правилу WHEREпункту набагато простіше слідувати:

Умова пошуку застосовується до кожного рядка T. Результатом пункту де є таблиця тих рядків Т, для яких результат умови пошуку істинний.

Простий англійською мовою рядки, які оцінюються UNKNOWNяк видалені, вилучаються із набору результатів.


5

У Technet є гарне пояснення того, як працюють нульові значення.

Нульове означає невідоме.

Тому булевий вираз

value = null

не оцінюється як false, воно оцінюється як null, але якщо це кінцевий результат пункту де, тоді нічого не повертається. Це практичний спосіб зробити це, оскільки повернути нуль було б важко уявити.

Цікаво і дуже важливо зрозуміти наступне:

Якщо в запиті у нас є

where (value=@param Or @param is null) And id=@anotherParam

і

  • значення = 1
  • @param є нульовим
  • id = 123
  • @ anotherParam = 123

тоді

"value = @ param" оцінює до null
"@param is null" оцінює до true
"id = @ otherParam" оцінює до true

Так вираз, який оцінюється, стає

(null Або true) І правда

Ми можемо спокуситись думати, що тут "null Or true" буде оцінено як null, і, таким чином, весь вираз стане нульовим і рядок не повернеться.

Це не так. Чому?

Оскільки "null Or true" оцінюється як true, що дуже логічно, оскільки якщо один операнд правдивий з оператором Or, то незалежно від значення іншого операнда, операція повернеться в true. Таким чином, не має значення, що інший операнд невідомий (null).

Отже, ми нарешті маємо true = true і таким чином рядок буде повернуто.

Примітка: з тією ж кришталево чистою логікою, що "null Or true" оцінює до true, "null And true" оцінює до null.

Оновлення:
Гаразд, просто для завершення я хочу додати і решту сюди, що виявляється досить цікавим стосовно вищезазначеного.

"null Або false" оцінює до null, "null And false" оцінює до false. :)

Логіка, звичайно, все ще така самоочевидна, як і раніше.


4

Тому що NULLозначає "невідоме значення" і два невідомі значення не можуть бути однаковими.

Отже, якщо за нашою логікою NULLN ° 1 дорівнює NULLN ° 2, ми повинні якось сказати:

SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)

де відоме значення -1N ° 1 дорівнює -1N ° 2


nullParam1 = -1і nullParam2 =NULLавіакатастрофа .... повинна бутиISNULL(NULLIF(@nullParam1, @nullParam2), NULLIF(@nullParam2, nullParam1)) IS NULL
Селвін

4

Усі відповіді тут здаються з точки зору CS, тому я хочу додати його з точки зору розробника.

Для розробника NULL дуже корисний. Відповіді тут кажуть, що NULL означає невідоме, і, можливо, в теорії CS це правда, не пам’ятайте, минув час. В реальному розвитку, хоча, принаймні з мого досвіду, це відбувається приблизно в 1% часу. Інші 99% використовуються для випадків, коли значення не є НЕВІДОМЛЕНО, але воно ЗНАЄТЬСЯ бути АБСЕНТОМ.

Наприклад:

  • Client.LastPurchase, для нового клієнта. Невідомо, що відомо, що він ще не зробив покупки.

  • Під час використання ORM з відображенням таблиці за ієрархією класів деякі значення просто не відображаються для певних класів.

  • Під час відображення структури дерева зазвичай матиме коріньParent = NULL

  • І багато іншого...

Я впевнений, що більшість розробників в якийсь момент написали WHERE value = NULL, що не отримали жодних результатів, і саме так вони дізналися про IS NULLсинтаксис. Подивіться, скільки голосів має це питання та пов'язані між собою.

Бази даних SQL є інструментом, і вони повинні бути розроблені таким чином, щоб їх користувачі легше зрозуміли.


1
Начебто всі кричать "NULL невідомо", а потім виправдовують свою поведінку. Так, якщо це приміщення, то, можливо, відповідь 3VL. Але майже у всіх БД, над якими я працюю, NULL означає відсутність. Вибачте, ваш голос загубився в пустелі @AlexDev
Джон Різ

3

NULL не рівний нічому, навіть самому собі. Моє особисте рішення щодо розуміння поведінки NULL - уникати використання її максимально :).


1
може бути рівним усьому, як це стосується лівого / правого / зовнішнього з’єднання ...
Мігель Вентура

5
Яка дурна непродуктивна відповідь. Те саме могло б сказати елементарним дітям про алгебру, але, не визнаючи насправді того, що намагається вирішити, це просто вийшло би таким нерозумним, що це робилося.
Еван Керролл

2
@Evan: Насправді, уникати NULL - це надійне рішення. 3-цінна логіка не є суперечливою, і багато людей вважають, що SQL було б краще без NULL та всієї (необхідної) складності, що це спричиняє.
sleske

3
"Багато людей" - це непомітне слово, а "не суперечливий" - це спосіб замаскувати більш простий "суперечливий" з яких 3VL не є.
Еван Керролл

"NULL не рівний нічому, навіть самому собі." ідучи за цією логікою, <somevalue>! = NULL має повернути true. Однак у дивному всесвіті SQL це помилково.
Том Лінт

3

Питання:
Чи дорівнює один невідомий інший невідомий?
(NULL = NULL) На
це запитання ніхто не може відповісти, тому він за замовчуванням відповідає істинному чи хибному, залежно від налаштувань ansi_nulls.

Однак питання:
чи невідома ця змінна?
Це питання зовсім інше і на нього можна відповісти правдиво.

nullVariable = null порівнює значення
nullVariable is null порівнює стан змінної


3

Плутанина виникає з рівня опосередкованості (абстракції), що виникає внаслідок використання NULL .

Повертаючись до аналогії "що знаходиться під ялинку", "Невідомо" описує стан знань про те, що знаходиться в коробці А.

Отже, якщо ви не знаєте, що знаходиться в коробці A, ви кажете, що це "Невідомо", але це не означає, що "Невідомо" всередині поля . Щось, крім невідомого, є у вікні, можливо, якийсь предмет або, можливо, нічого немає в коробці.

Так само, якщо ви не знаєте, що знаходиться у графі В, ви можете позначити свій стан знань про вміст як "Невідомий".

Отож ось і кікер: Твій стан знань про Box А одно вашому рівню знань про Графа . (Ваш стан знань в обох випадках "Невідомий" або "Я не знаю, що знаходиться в коробці".) Але вміст коробок може бути або не бути рівним.

Повертаючись до SQL, в ідеалі ви маєте змогу порівнювати значення лише тоді, коли знаєте, що вони є. На жаль, мітка, яка описує брак знань, зберігається у самій комірці , тому ми спокушаємося використовувати її як значення. Але ми не повинні використовувати це як значення, оскільки це призвело б до того, що "вміст поля A дорівнює вмісту поля B, коли ми не знаємо, що знаходиться у вікні A та / або ми не знаємо, що знаходиться у вікні B. (Логічно, що "якщо я не знаю, що знаходиться в коробці А, і якщо я не знаю, що знаходиться в коробці В, то те, що знаходиться в полі А = що є в коробці В", є помилковим.)

Так, мертвий кінь.


3

У MSDN є чудова описова стаття про нулі та три логіки стану, які вони породжують.

Коротше кажучи, специфікація SQL92 визначає NULL як невідомий, а NULL, що використовується в наступних операторах, викликає несподівані результати для непосвячених:

= operator NULL   true   false 
NULL       NULL   NULL   NULL
true       NULL   true   false
false      NULL   false  true

and op     NULL   true   false 
NULL       NULL   NULL   false
true       NULL   true   false
false      false  false  false

or op      NULL   true   false 
NULL       NULL   true   NULL
true       true   true   true
false      NULL   true   false

Але питання не в тому, що 3VL (тризначна логіка) полягає в рефлексивному властивості рівності.
MaD70

Якщо бути точнішим, як я нарешті детально розказав у своїй відповіді, проблеми виникають, коли рівність інтерпретується в 3VL, так що рефлексивна властивість рівності не завжди оцінюється як істинна.
MaD70

1

null невідомий у sql, тому ми не можемо очікувати, що дві невідомі будуть однаковими.

Однак ви можете отримати таку поведінку, встановивши ANSI_NULLS на Вимкнено (його увімкнено за замовчуванням). Ви зможете використовувати = оператор для нулів

SET ANSI_NULLS off
if null=null
print 1
else 
print 2
set ansi_nulls on
if null=null
print 1
else 
print 2

2
Це всі види ні . У світі є визначення null, навчіться його розуміти або просто змінити таблицю, щоб мати типи int та оновити стовпці.
Еван Керролл

3
Я дійсно не рекомендував вимкнути SET ANSI_NULLS. Я дізнався про ANSI_NULLS важким шляхом. Але завжди добре знати всі варіанти, наявні спеціально, коли ви натрапляєте на рядок, який говорить, де SomeId = null Як би ви мали сенс цього рядка, не знаючи про ANSI_NULLS. Те, як я це виглядаю, мій пост був корисним .. :)
пс.

1

Ви працюєте в уряді, реєструючи інформацію про громадян. Сюди входить національний посвідчення особи для кожної людини в країні. Дитину залишили біля дверей церкви близько 40 років тому, ніхто не знає, хто їхні батьки. Ідентифікатор батька цієї особи є NULL. Двох таких людей існує. Порахуйте людей, які поділяють одне і те ж посвідчення батька хоча б з однією іншою людиною (люди, які є побратимами). Чи рахуєте ви і цих двох?

Відповідь "ні", ви не знаєте, тому що ми не знаємо, чи вони рідні брати чи ні.

Припустимо, у вас немає NULLопції, а замість цього використовуйте якесь заздалегідь визначене значення для відображення "невідомого", можливо, порожній рядок або число 0 або символ * і т.д. , 0 = 0 і "" = "" і т. Д. Це не те, чого ви хочете (як показано в наведеному вище прикладі), і як ви часто можете забути про ці випадки (приклад, наведений вище, - це явна облямованість поза звичайним щоденним мисленням ), тоді вам потрібна мова, щоб запам'ятати вам, що NULL = NULLне відповідає дійсності.

Необхідність - це винахідництво.


0

Просто доповнення до інших чудових відповідей:

AND: The result of true and unknown is unknown, false and unknown is false,
while unknown and unknown is unknown.

OR: The result of true or unknown is true, false or unknown is unknown, while unknown or unknown is unknown.

NOT: The result of not unknown is unknown

0

Якщо ви шукаєте вираз, що повертає істину для двох NULL, ви можете використовувати:

SELECT 1 
WHERE EXISTS (
    SELECT NULL
    INTERSECT
    SELECT NULL
)

Це корисно, якщо ви хочете копіювати дані з однієї таблиці в іншу.


0

Тест на рівність, наприклад, у викладі справи, коли застереження, може бути змінений з

XYZ = NULL 

до

XYZ IS NULL

Якщо я хочу вважати пробіли та порожні рядки рівними NULL, я часто також використовую тест рівності, наприклад:

(NULLIF(ltrim( XYZ ),'') IS NULL)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.