Чому Oracle 9i розглядає порожній рядок як NULL?


218

Я знаю , що це дійсно вважають «» , як NULL, але це не робить багато , щоб сказати мені , чому це так. Наскільки я розумію специфікації SQL, `` '' - це не те саме, що NULL- одне є дійсним даним, а інше вказує на відсутність тієї самої інформації.

Не соромтеся міркувати, але, будь ласка, вкажіть, чи це так. Якщо хтось із Oracle може коментувати це, це було б фантастично!


10
Не соромтеся спекулювати? Якось не думаю, що це дасть вам найбільший набір відповідей ..
SCdF

1
Я гадаю, ні, але я не був впевнений, що буде якась впевненість у цьому питанні, тому я вирішив, що відчиню двері. Здається, поки що все вийшло нормально.
Chris R,


Відповіді:


221

Я вважаю, що відповідь така: Oracle дуже і дуже стара.

Ще в старі часи, поки не було стандарту SQL, Oracle прийняв дизайнерське рішення, що порожні рядки в VARCHAR/ VARCHAR2стовпцях є NULLі що є лише одне значення NULL (є реляційні теоретики, які розрізнятимуть дані, про які ніколи не вимагали, дані, де відповідь існує, але невідома користувачеві, дані, коли відповіді немає, і т. д. все це становить певний сенс NULL).

На той час, коли з'явився стандарт SQL і погодився, що NULLі порожній рядок є окремими сутностями, вже існували користувачі Oracle, які мали код, який вважав, що ці два еквівалентні. Отже, Oracle в основному залишали варіанти злому існуючого коду, порушення стандарту SQL або введення якогось параметра ініціалізації, який змінить функціональність потенційно великої кількості запитів. Порушення стандарту SQL (IMHO) було найменш руйнівним із цих трьох варіантів.

Oracle залишив відкритою можливість того, що VARCHARтип даних зміниться в майбутньому випуску, щоб відповідати стандарту SQL (саме тому всі користуються VARCHAR2Oracle, оскільки поведінка цього типу даних гарантовано залишатиметься незмінною).


61

Том Кайт, віце-президент Oracle:

Varchar з нульовою довжиною розглядається як NULL.

'' не розглядається як NULL.

'' при призначенні символу (1) стає '' (типи символів - це порожні заповнені рядки).

'' при присвоєнні varchar2 (1) стає '', який є рядком нульової довжини, а рядок нульової довжини має значення NULL в Oracle (він не довгий '')


17
Ого, Том досить хитрий. Враховуючи, що питання стосуються надзвичайної розбіжності з SQL92, можна подумати, що він був би менш виразним з цього приводу ... хоча він може втомитися відповідати.
Chris R,

8
Найкраще в Томі - це те, що ви отримаєте чітку відповідь, де точно зазначено , що він думає. Шукайте деякі коментарі, де люди використовували текст, говорять на Ask Tom
Chris Gill

9
Але було б точніше, якби другий рядок було змінено на '', не завжди трактується як NULL.
ypercubeᵀᴹ

3
@ypercube Цитата не стає більш точною, змінюючи слово, яке фактично вживав Том. Якщо ви думаєте, Том сформулював це заплутано, ммм. Можливо. Я думаю, що він місці . Найбільш заплутані ситуації виникають, коли ''він неявно перетворюється на VARCHAR2, такий як cast('' as char(1)) is nullце ... напрочуд ІСТИНА
sehe

1
@sehe заплутаним бітом для мене є вибір 1 із подвійного де (`` нульовий)
matt freake

20

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


6
Це має сенс лише в тому випадку, якщо ви вважаєте, що кожне поле в системі введення даних є обов’язковим. Невідповідь на необов’язкове поле (наприклад, «Ім'я собаки») є допустимою, тому порожній рядок все ще має відмінне призначення від NULL. Навіть маючи це припущення, я сумніваюся, що ранні розробники вважали Oracle «прославленим серверним середовищем для системи введення даних», тому я не впевнений, що ця відповідь взагалі має сенс.
Джаред,

19

Документація Oracle попереджає розробників про цю проблему, повертаючись принаймні до версії 7.

Oracle вирішив представляти NULLS методом "неможливого значення". Наприклад, NULL у числовому розташуванні буде зберігатися як "мінус нуль", неможливе значення. Будь-які мінусові нулі, отримані в результаті обчислень, будуть перетворені в додатні нулі перед збереженням.

Oracle також помилково вирішив вважати рядок VARCHAR довжиною нуль (порожній рядок) неможливим значенням і відповідним вибором для представлення NULL. Виявляється, порожній рядок далекий від неможливого значення. Це навіть ідентичність під час операції конкатенації рядків!

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

Існують способи позначення NULLS, крім неможливих значень, але Oracle їх не використовував.

(Я використовую слово "розташування" вище, щоб означати перетин рядка і стовпця.)


Документація Oracle попереджає розробників та розробників баз даних, що деякі майбутні версії Oracle можуть порушити цю асоціацію між порожнім рядком і NULL, а також розбити будь-який код, який залежить від цієї асоціації - чи можете ви надати посилання на це твердження?
Piotr Dobrogost


1

Порожній рядок - це те саме, що NULL, просто тому, що він є "меншим злом" у порівнянні з ситуацією, коли ці два (порожній рядок і null) не однакові.

У мовах, де NULL і порожній рядок не однакові, потрібно завжди перевіряти обидві умови.


1
Просто встановіть not nullобмеження на стовпець і перевіряйте лише порожній рядок.
Єгор Скриптунов

6
Перевірка обох умов є тривіальною: WHERE Field <> ''повертає true, лише якщо поле не NULL і не порожнє, у базах даних з поведінкою ANSI для порожніх рядків.

1

За офіційними документами 11g

В даний час Oracle Database обробляє значення символу довжиною нуль як нуль. Однак це може не продовжувати бути правдою в майбутніх випусках, і Oracle рекомендує не поводитися з порожніми рядками так само, як з нулями.

Можливі причини

  1. val IS NOT NULL є більш читабельним, ніж val != ''
  2. Не потрібно перевіряти обидва умови val != '' and val IS NOT NULL

6
У базі даних, повністю сумісній з ANSI, не потрібно перевіряти обидві умови. val <> ''вже виключає NULL. Можливо, ви мали на увазі val = '' OR val IS NULL. Але порожні рядки, які не порівнюються як NULL, корисні !
ErikE

Я погоджуюся з частиною порівняння.
сортувальник

0

Приклад з книги

   set serveroutput on;   
    DECLARE
    empty_varchar2 VARCHAR2(10) := '';
    empty_char CHAR(10) := '';
    BEGIN
    IF empty_varchar2 IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_varchar2 is NULL');
    END IF;


    IF '' IS NULL THEN
    DBMS_OUTPUT.PUT_LINE(''''' is NULL');
    END IF;

    IF empty_char IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
    ELSIF empty_char IS NOT NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
    END IF;

    END;

-2

Тому що не трактувати це як NULL теж не особливо корисно.

Якщо ви помилитеся в цій галузі на Oracle, ви зазвичай помічаєте це відразу. Однак у SQL-сервері він працює, і проблема виникає лише тоді, коли хтось вводить порожній рядок замість NULL (можливо, з клієнтської бібліотеки .net, де null відрізняється від "", але ви зазвичай ставитеся до них однаково ).

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


2
Набагато, набагато простіше налагодити. Крім того, якщо ви бачите порожню комірку або введення на екрані, ви знаєте, що дані в БД є нульовими. В інших базах даних, де '' <> NULL, ви не можете "побачити", чи є дані нульовими або '', це призводить до дуже підлих помилок. '' = null це найрозумніший варіант, навіть якщо він не є стандартним.
Lucio M. Tato

3
“В інших базах даних, де '' <> NULL, ви не можете" побачити ", чи є дані нульовими або ''" => Зазвичай засоби БД відображають NULL інакше, ніж порожні рядки. Насправді навіть розробник Oracle SQL відображає NULL як "(null)". Я думаю, це для того, щоб відрізнити NULL від пробілів, але це не пов'язано з різницею між NULL та порожніми рядками.
Didier L

-6

Справді, у мене не було нічого, крім труднощів у роботі з Oracle, включаючи недійсні значення дати та часу (неможливо роздрукувати, перетворити або щось інше, просто подивившись за допомогою функції DUMP ()), які дозволено вставляти в базу даних, мабуть, через якусь глючку версія клієнта як двійковий стовпець! Стільки про захист цілісності бази даних!

Обробка Oracle посилань NULL:

http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/

http://jeffkemponoracle.com/2006/02/empty-string-andor-null.html


1
недійсні значення часу даних? Не знаю, що це означає. Ви розмістили це як запитання тут?

1
Проблема попередньо датувала stackoverflow - я не отримав корисної інформації з форумів Oracle і створив обхідний шлях - я відстежу свої примітки та розміщу тут.
Кейд Ру

Опубліковані деталі як запитання тут.
Кейд Ру

-6

Перш за все, нульові та нульові рядки не завжди трактувались Oracle як однакові. Нульовий рядок - це, за визначенням, рядок, що не містить символів. Це зовсім не те, що нуль. NULL - це, за визначенням, відсутність даних.

П’ять-шість років тому, близько того, нульовий рядок оброблявся Oracle не так, як нульовий. Хоча, як і нуль, нульовий рядок був рівним усьому і відрізнявся від усього (що, на мою думку, добре для нуля, але абсолютно НЕПРАВИЛЬНО для нульового рядка), принаймні довжина (нульовий рядок) повертала б 0, як слід, оскільки нульовий рядок є рядок нульової довжини.

В даний час в Oracle, length (null) повертає null, що, на мою думку, нормально, але length (null string) також повертає null, що є абсолютно НЕПРАВИЛЬНИМ.

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


1
Посилання потрібне для розрізнення "нульового рядка" та значення NULL. У будь-якій базі даних, крім Oracle, VARCHARполе може мати значення (нуль або більше символів) або відсутність значення (NULL), крапка.

"П'ять-шість років тому" з 2011 року потраплятиме у часові рамки 10 г (10,1 випущено 2003, 10,2 у 2005). 10g абсолютно не вніс жодних глобальних змін у обробці нулів, і ніколи не було жодної різниці між NULLрядком із нульовим значенням, і таке розмежування не має сенсу. Боюсь, що ця відповідь - повна фантазія.
Вільям Робертсон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.