Null (SQL)Null — спеціальне значення, яке використовується в SQL для позначення відсутності даних. NULL відповідає поняттю «порожнє поле», тобто «поле, яке не містить ніякого значення». Введено винахідником реляційної моделі даних Едгаром Коддом, SQL Null слугує для виконання вимоги, що всі дійсно реляційні системи керування базами даних (РСКБД) підтримують представлення «відсутньої і непридатної інформації». Кодд також ввів використання малої літери грецької омега (ω) як символу для представлення Null в теорії баз даних. Null був причиною суперечок і дебатів через свою асоціацію з трійковою логікою, особливих вимог з його використання в інструкції SQL JOIN, і спеціальної обробки агрегатними функціями та операторами групування SQL. Хоча особливі функції та предикати правильно обробляють Null, опоненти відчувають, що підтримка цієї можливості вводить непотрібну складність і суперечливість в реляційну модель даних. ІсторіяNull був введений Едгаром Коддом як засіб для представлення відсутніх даних в реляційній моделі незалежно від типу даних. В подальшому він опублікував свою статтю в двох частинах в часописі ComputerWorld[1][2], в цій статті він презентував 12 правил за якими можна визначити чи є СКБД дійсно реляційною.[3] Кодд також ввів тризначну логіку, яка має три значення істинності Істина (True), Хиба (False) та Невідомо (Unknown), яка дуже близька до концепції Null. Значення Невідомо генерується коли Null порівнюється з будь-яким значенням даних або з Null. У своїй книзі «The Relational Model for Database Management, Version 2» Кодд, зазначив, що єдиний Null прийнятий в стандарті SQL недостатній, і має бути замінений двома різними Null значеннями для позначення причини відсутності. Ці дві Null-позначки зазвичай згадується як А-значення (A-Values) та І-значення (I-Values), що представляють Відсутній та прийнятний (Missing But Applicable) та Відсутній та неприйнятний (Missing But Inapplicable) відповідно.[4] Рекомендація Кодда вимагала розширення логічної структури SQL для відповідності чотиризначній логічній системі. Через цю додаткову складність ідея не отримала широко розповсюдження. Тризначна логікаЧерез те, що Null не є членом будь-якого домену даних, ми його не сприймаємо як значення, радше як позначку відсутності даних. Через це порівняння з Null ніколи не дасть в результаті Істина або Хиба, результат буде завжди третім логічним значенням, Невідомо.[5] Логічний результат наступного виразу, що порівнює 10 з Null, Невідомо: SELECT 10 = NULL -- В результаті Невідомо
Однак, певні вирази з Null можуть повертати значення якщо Null не впливає на вихідне значення виразу. Припустимо, що в наступному прикладі другий операнд обчислюється тільки якщо в цьому виникла потреба: SELECT TRUE OR NULL -- В результаті Істина
В цьому випадку факт того, що значення праворуч від OR невідоме не впливає на кіневий результат. SQL реалізує три логічних значення, таким чином реалізації SQL мають забезпечувати тризначну логіку. Керівні правила тризначної логіки в SQL показані в таблиці нижче (p і q представляють логічні стани)"[6]
Базові оператори порівняння в SQL завжди повертають Невідомо коли щось порівнюється з Null, таким чином стандарт SQL забезбечує два спеціальних порівняльних пердиката для Null. Типізація данихNull в SQL нетипізований, тобто він не розпізнається як ціле, символ чи будь-який інший тип даних.[5] Через це, часом дуже важливо явно приводити Null до певного типу даних. Наприклад, якщо перевантажені функції підтримуються РСКБД, SQL може бути неспроможним автоматично вибрати правильну функцію без знання типів даних всіх параметрів, включно з тими де передається Null. Мова маніпулювання данимиТризначна логіка SQL зустрічається в мові маніпулювання даними в предикатах порівняння в DML виразах і запитах. Пункт SELECT *
FROM t
WHERE i = NULL;
Наведений запит завжди буде повертати нуль рядків через те, що порівняння стовпця i з Null завжди дає Невідомо, навіть для рядків де i дорівнює Null, що змушує CASE виразиSQL вирази SELECT CASE i WHEN NULL THEN 'Is Null' -- Цей варіант ніколи не спрацює
WHEN 0 THEN 'Is Zero' -- Спрацює коли i = 0
WHEN 1 THEN 'Is One' -- Спрацює коли i = 1
END
FROM t;
Завдяки тому, що Пошуковий вираз SELECT CASE WHEN i IS NULL THEN 'Null Result' -- Спрацює коли i буде NULL
WHEN i = 0 THEN 'Zero' -- Спрацює коли i = 0
WHEN i = 1 THEN 'One' -- Спрацює коли i = 1
END
FROM t;
В пошуковому виразі Check constraintПервинне місце де тризначна логіка SQL перетинається з SQL мовою опису даних (DDL) це в формі check constraint . Перевірка на обмеження розміщена на ствопці діє за дещо різними правила порівняно з DML пунктом CREATE TABLE t (
i INTEGER,
CONSTRAINT ck_i CHECK ( i < 0 AND i = 0 AND i > 0 ) );
Для заборони вставлення значень Null, можна застосувати CREATE TABLE t ( i INTEGER NOT NULL );
Процедурні розширенняSQL/PSM (SQL Persistent Stored Modules) визначає процедурні розширення для SQL, такі як вираз IF i = NULL THEN
SELECT 'Результат Істина'
ELSEIF NOT(i = NULL) THEN
SELECT 'Результат Хиба'
ELSE
SELECT 'Результат Невідомо';
Вираз Об'єднанняЗовнішнє об'єднання в SQL, включно з лівим зовнішнім об'єднанням, правим зовнішнім об'єднанням та повним зовнішнім об'єднанням, автоматично підставляє Null як заповнювач для відсутніх значень у відповідних таблицях. Наприклад, для лівих зовнішніх об'єднань Null генерується на місцях з таблиць, що знаходяться праворуч від оператора Перша таблиця (Employee) містить ID службовців та імена, тоді як друга таблиця (PhoneNumber) містить відповідно ID службовців та телефонні номери.
Наступний SQL запит виконує ліве зовнішнє об'єднання на цих двох таблицях. SELECT e.ID, e.LastName, e.FirstName, pn.Number
FROM Employee e
LEFT OUTER JOIN PhoneNumber pn
ON e.ID = pn.ID;
Результатний набір цього запиту показує як SQL використовує Null як замінник для значень відсутніх в таблиці PhoneNumber.
Внутрішнє об'єднання, яке також присутнє в стандарті SQL, не продукує Null замість відсутніх значень в відповідних таблицях. Треба бути обережним використовуючи стовпці з можливими значеннями Null в критеріях об'єднань SQL. Через те, що Null не дорівнює іншому Null, Null в стовпці однієї таблиці не буде об'єдуватись з Null в парній таблиці шляхом використання стандартних операторів для перевірки рівності. SQL функція Наступний вираз перевіряє на рівність значення A і B і трактує Null-и як рівні значення. Оператор IFNULL( A = B, FALSE ) OR ( A IS NULL AND B IS NULL )
Математичні операції та об'єднання рядківЧерез те, що Null не тип даних, а просто позначка невідомого значення, використання математичних операторів з Null повертає невідоме значення, яке представляється за допомогою Null.[9] В наступному прикладі, добуток 10 та Null повертає Null: 10 * NULL -- Результат NULL
Це може призвести до неочікуваних результатів. Наприклад, при спробі розділити Null на нуль, платформа може повернути Null замість генерування помилки ділення на нуль ("data exception - division by zero").[9]. Хоч поведінка в цій ситуації не визначена стандартом ISO SQL багато СКБД трактують цю операцію схожим чином. Наприклад, Oracle, PostgreSQL, MySQL Server і Microsoft SQL Server повернуть Null як результат наступного виразу: NULL / 0
Операція конкатенації рядків, яка часто зустрічається в SQL, також продукує Null коли один з операндів Null[10]. Наступний приклад показує, як результат Null буде повернений при використанні Null у SQL-операції з'єднання стрічок з використанням оператора 'Fish ' || NULL || 'Chips' -- Результат NULL
Це не вірно для всіх реалізацій баз даних. Наприклад, в Oracle NULL та порожній рядок трактуються однаково, таким чином 'Fish ' || NULL || 'Chips' повертає 'Fish Chips'. Агрегатні функціїSQL визначає агрегатні функції для спрощення агрегатних обчислень на сервері. Майже всі агрегатні функції виконують крок з виключення Null, таким чином Null значення не включаються в результат обчислень.[11] Таке неявне виключання Null може відбитися на результаті обчислень агрегатної функції. Наступна таблиця видає різні результати для кожного стовпця при застосуванні агрегатної функції
Агрегатна функція Групування та сортуванняЧерез те, що SQL:2003 визначає позначки Null як нерівні одна одній, додаткове визначення було необхідне для групування Null разом при виконанні певних операцій. SQL визначає «будь-які два значення, які рівні між собою або будь-які два Null»", як «нерізні».[12] Це визначення «нерізності» для групування та сортування позначок Nulls коли пункт Інші SQL оператори, вирази та ключові слова використовують «нерізні» в їхньому трактуванні позначок Null. Вірно для наступних:
Стандарт SQL не визначає явно порядок сортування за умовчанням для позначок Null. Замість цього, Null можуть бути відсортовані перед або після всіх даних, використовуючи Функції обробки NullSQL визначає дві функції обробки Null: COALESCEФункція COALESCE(value1, value2, value3, ...)
CASE WHEN value1 IS NOT NULL THEN value1
WHEN value2 IS NOT NULL THEN value2
WHEN value3 IS NOT NULL THEN value3
...
END
Деякі SQL СКБД реалізують специфічні функції подібні до NULLIF або NVLФункція NULLIF(value1, value2)
Тобто, CASE WHEN value1 = value2 THEN NULL ELSE value1 END
Вираз COALESCE ( val1, ... , val{n} )
переходить в: NVL( val1 , NVL( val2 , NVL( val3 , ... , NVL ( val{n-1} , val{n} ) ... )))
СуперечкаЗагальні помилкиНеправильне розуміння як Null працює стає причиною великої кількості помилок в SQL коді, як в ISO SQL виразах, так і в специфічних діалектах SQL реальних систем баз даних. Ці помилки зазвичай виникають в результаті плутання між Null і або 0 (нуль), або порожнім рядком (рядком зі значенням нульової довжини, представленим в SQL як Наприклад, пункт SELECT *
FROM sometable
WHERE num <> 1; -- Рядки де num є NULL не будуть повернуті,
-- протилежно до очікувань багатьох користувачів.
Схожим чином, Null значення часто плутають з порожніми рядками. Припустимо існування функції SELECT *
FROM sometable
WHERE LENGTH(string) < 20; -- Рядки де NULL не будуть повернуті.
Це ускладнюється фактом, що деякі утіліти показують NULL як порожній рядок, і порожній рядок може бути невірно збережений як NULL. КритикаРеалізація Null в ISO SQL є предметом критики, суперечок і закликів до змін. Існують різні думки з цього приводу:
Закон виключеного третьогоSQL дозволяє три логічні вибори: істина, хиба і невідомо, що означає, що SQL неминуче ігнорує закон виключеного третього. Коротко закон стверджує, для отримання протилежного результату до будь-якого логічного результату достатньо застосувати оператор логічного «заперечення». Однак, його неможливо застосувати до SQL Null. Керуючись законом виключеного третього, наступний логічний вираз може бути спрощений: SELECT * FROM stuff WHERE ( x = 10 ) OR NOT ( x = 10 );
Закон виключеного третього дозволяє спрощення предикату в пункті WHERE, отримавши в результаті наступне: SELECT * FROM stuff;
Це не спрацює в SQL, через те, що x стовпець може містити Null, що призведе до повернення додаткових рядків. Насправді: SELECT * FROM stuff;
-- (через тризначну логіку) тотожно з:
SELECT * FROM stuff WHERE ( x = 10 ) OR NOT ( x = 10 ) OR x IS NULL;
Тобто, для вірного спрощення першого виразу в SQL необхідно повертати всі рядки де х не Null. SELECT * FROM stuff WHERE x IS NOT NULL;
Ігнорування закону виключеного третього вводить додаткову складність в логіку SQL, спроби застосувати це правило в тризначній логіці SQL призводить фальшивої дихотомії. Примітки
|