Dlaczego Oracle 9i traktuje pusty ciąg znaków jako NULL?

216

Wiem, że nie uważają „” tak NULL, ale to nie robi wiele, aby mi powiedzieć, dlaczego tak jest. Jak rozumiem specyfikacje SQL, „” nie jest tym samym, co NULL- jeden jest prawidłowym układem odniesienia, a drugi wskazuje na brak tych samych informacji.

Możesz spekulować, ale proszę wskazać, czy tak jest. Gdyby ktoś z Oracle mógł to skomentować, byłoby fantastycznie!

Chris R.
źródło
9
Zapraszam do spekulacji? Jakoś nie sądzę, że dostarczy ci najlepszego zestawu odpowiedzi.
SCdF
1
Chyba nie, ale nie byłem pewien, czy w tej sprawie będzie jakaś pewność, więc pomyślałem, że otworzę drzwi. Wygląda na to, że jak dotąd wszystko ułożyło się dobrze.
Chris R
Powiązane: dba.stackexchange.com/q/49744/56961
AlikElzin-kilaka 21.04.16

Odpowiedzi:

216

Wierzę, że odpowiedź jest taka, że ​​Oracle jest bardzo, bardzo stara.

W dawnych czasach, zanim istniał standard SQL, Oracle podjęło decyzję projektową, że puste ciągi w VARCHAR/ VARCHAR2kolumnach są NULLi że istnieje tylko jedno wyczucie NULL (istnieją teoretycy relacyjni, którzy rozróżniają dane, o które nigdy nie pytano, dane, na które odpowiedź istnieje, ale nie są znane użytkownikowi, dane, na które nie ma odpowiedzi itp., z których wszystkie stanowią pewien sens NULL).

Zanim pojawił się standard SQL i zgodził się na to, NULLa pusty ciąg znaków był odrębną jednostką, już byli użytkownicy Oracle, którzy mieli kod, który zakładał, że oba są równoważne. Tak więc Oracle zasadniczo pozostawiono z opcją złamania istniejącego kodu, naruszenia standardu SQL lub wprowadzenia pewnego rodzaju parametru inicjującego, który zmieniłby funkcjonalność potencjalnie dużej liczby zapytań. Naruszenie standardu SQL (IMHO) było najmniej zakłócające z tych trzech opcji.

Oracle pozostawił otwartą możliwość VARCHARzmiany typu danych w przyszłej wersji, aby dostosować się do standardu SQL (dlatego wszyscy używają VARCHAR2w Oracle, ponieważ zachowanie tego typu danych z pewnością pozostanie takie samo w przyszłości).

Justin Cave
źródło
60

Tom Kyte Wiceprezes Oracle:

Varchar długości ZERO jest traktowany jako NULL.

„” nie jest traktowane jako NULL.

„” po przypisaniu do znaku (1) staje się „” (typy znaków to puste łańcuchy dopełniane).

„Gdy przypisany do varchar2 (1) staje się„ ”, który jest łańcuchem zerowej długości, a ciąg zerowy ma wartość NULL w Oracle (nie jest długi”)

Brian
źródło
17
Wow, Tom jest dość wredny. Biorąc pod uwagę, że pytania dotyczą rażącej rozbieżności z SQL92, można by pomyśleć, że byłby mniej ponury ... chociaż może być zmęczony odpowiedzią.
Chris R
8
Najlepszą rzeczą w Tomie jest to, że otrzymujesz jasną odpowiedź, która dokładnie mówi , co on myśli. Spójrz na niektóre komentarze, w których ludzie używali tekstu, mówią na Ask Tom
Chris Gill
9
Ale byłoby bardziej precyzyjnie, gdyby druga linia została zmieniona na „” nie zawsze jest traktowana jako NULL.
ypercubeᵀᴹ
2
@ypercube Cytat nie staje się bardziej precyzyjny przez zmianę słowa faktycznie używanego przez Toma. Jeśli uważasz, że Tom sformułował to myląco, mmm. Może. Myślę, że jest na miejscu . Najbardziej zagmatwane sytuacje powstają, gdy ''jest się domyślnie konwertowany na VARCHAR2, taki jak ten, cast('' as char(1)) is nullktóry jest ... zaskakująco PRAWDZIWY
patrz
1
@to mylący dla mnie bit to wybierz 1 z dual, gdzie ('' jest zerowy)
Matt Freake
20

Podejrzewam, że ma to o wiele więcej sensu, jeśli myślisz o Oracle tak, jak to robili wcześniej programiści - jako chwalebny backend dla systemu wprowadzania danych. Każde pole w bazie danych odpowiadało polu w postaci, którą operator wprowadzania danych widział na swoim ekranie. Jeśli operator nie wpisał niczego w polu, niezależnie od tego, czy jest to „data urodzenia”, czy „adres”, dane dla tego pola są „nieznane”. Operator nie ma możliwości wskazania, że ​​czyjś adres jest naprawdę pustym ciągiem, a to i tak nie ma większego sensu.

użytkownik67897
źródło
5
Ma to sens tylko wtedy, gdy założymy, że każde pole w systemie wprowadzania danych jest obowiązkowe. Brak odpowiedzi na pole nieobowiązkowe (np. „Imię psa”) jest prawidłowy, więc pusty ciąg znaków nadal ma inny cel niż NULL. Nawet przy takim założeniu wątpię, aby wcześni programiści myśleli o Oracle jako o „chwalebnym zapleczu dla systemu wprowadzania danych”, więc nie jestem pewien, czy ta odpowiedź w ogóle ma sens.
Jared
19

Dokumentacja Oracle ostrzega programistów o tym problemie, sięgając przynajmniej do wersji 7.

Oracle wybrał reprezentowanie wartości NULLS techniką „niemożliwej wartości”. Na przykład NULL w lokalizacji numerycznej zostanie zapisany jako „minus zero”, niemożliwa wartość. Wszelkie zera ujemne wynikające z obliczeń zostaną przekonwertowane na zero dodatnie przed zapisaniem.

Oracle również błędnie wybrało uznanie ciągu VARCHAR o długości zero (pusty ciąg) za wartość niemożliwą i odpowiedni wybór do reprezentowania wartości NULL. Okazuje się, że pusty ciąg jest daleki od niemożliwej wartości. To nawet tożsamość w ramach operacji łączenia łańcuchów!

Dokumentacja Oracle ostrzega projektantów i programistów baz danych, że niektóre przyszłe wersje Oracle mogą zerwać to powiązanie między pustym ciągiem znaków a wartością NULL, a także zerwać dowolny kod zależny od tego powiązania.

Istnieją techniki oznaczania wartości NULLS inne niż wartości niemożliwe, ale Oracle ich nie używała.

(Używam słowa „lokalizacja” powyżej, oznaczającego przecięcie wiersza i kolumny).

Walter Mitty
źródło
Dokumentacja Oracle ostrzega projektantów i programistów baz danych, że niektóre przyszłe wersje Oracle mogą przerwać to powiązanie między pustym ciągiem znaków a wartością NULL i złamać dowolny kod zależny od tego powiązania - czy możesz podać odniesienie do tego oświadczenia?
Piotr Dobrogost
2

Pusty ciąg znaków jest taki sam jak NULL po prostu dlatego, że jest „mniejszym złem” w porównaniu z sytuacją, gdy dwa (pusty ciąg i zero) nie są takie same.

W językach, w których NULL i pusty ciąg znaków nie są takie same, zawsze należy sprawdzić oba warunki.

Alex Kreutznaer
źródło
Po prostu ustaw not nullograniczenie dla kolumny i zaznacz tylko pusty ciąg.
Egor Skriptunoff,
6
Sprawdzanie obu warunków jest banalne: WHERE Field <> ''zwraca wartość true tylko wtedy, gdy pole nie ma wartości NULL i nie jest puste, w bazach danych z zachowaniem ANSI dla pustych łańcuchów.
1

Według oficjalnych dokumentów 11g

Baza danych Oracle traktuje obecnie wartość znaku o długości zero jako zero. Jednak może to nie być prawdą w przyszłych wydaniach, a Oracle zaleca, aby nie traktować pustych ciągów znaków tak samo jak wartości zerowych.

Możliwe przyczyny

  1. val IS NOT NULL jest bardziej czytelny niż val != ''
  2. Nie trzeba sprawdzać obu warunków val != '' and val IS NOT NULL
Sorter
źródło
5
W bazie danych w pełni zgodnej z ANSI nie musisz sprawdzać obu warunków. val <> ''już wyklucza NULL. Być może miałeś na myśli val = '' OR val IS NULL. Ale przydatne są puste ciągi, które nie są porównywane jako NULL !
ErikE
Zgadzam się z częścią porównawczą.
Sorter
0

Przykład z książki

   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;
zloctb
źródło
-1

Ponieważ nie traktowanie go jako NULL również nie jest szczególnie pomocne.

Jeśli popełnisz błąd w tym obszarze na Wyroczni, zwykle natychmiast zauważysz. Jednak na serwerze SQL wydaje się działać, a problem pojawia się tylko wtedy, gdy ktoś wprowadzi pusty ciąg zamiast NULL (być może z biblioteki klienta .net, gdzie null różni się od „”, ale zwykle traktuje się je tak samo ).

Nie twierdzę, że Oracle ma rację, ale wydaje mi się, że oba sposoby są w przybliżeniu jednakowo złe.

erikkallen
źródło
2
Znacznie łatwiejsze do debugowania. Ponadto, jeśli zobaczysz pustą komórkę lub dane wejściowe na ekranie, wiesz, że dane w bazie danych są zerowe. W innych bazach danych, gdzie „<> NULL”, nie można „zobaczyć”, czy dane są zerowe lub „”, prowadzi to do bardzo podstępnych błędów. '' = null to najrozsądniejsza opcja, nawet jeśli nie jest standardowa.
Lucio M. Tato
2
„W innych bazach danych, w których„ ”<> NULL, nie można„ zobaczyć ”, czy dane są puste lub„ ”” => Zazwyczaj narzędzia DB wyświetlają wartości NULL inaczej niż puste ciągi. W rzeczywistości nawet Oracle SQL Developer pokazuje wartości NULL jako „(null)”. Wydaje mi się, że ma to na celu odróżnienie wartości NULL od białych znaków, ale nie jest to związane z różnicą między wartościami NULL i pustymi ciągami.
Didier L
-6

Rzeczywiście, miałem tylko trudności w radzeniu sobie z Oracle, w tym niepoprawne wartości daty / godziny (nie można ich wydrukować, przekonwertować ani nic, po prostu spojrzał na funkcję DUMP ()), które mogą być wstawiane do bazy danych, najwyraźniej przez jakiś błąd wersja klienta jako kolumna binarna! Tyle o ochronie integralności bazy danych!

Obsługa linków NULL przez Oracle:

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

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

Cade Roux
źródło
1
nieprawidłowe wartości datatime? Nie jestem pewna co to oznacza. Czy opublikowałeś to tutaj jako pytanie?
1
Problem przed datą przepełnienia stosu - nie otrzymałem żadnych przydatnych informacji z forów Oracle i stworzyłem obejście - wyśledzę swoje notatki i opublikuję tutaj.
Cade Roux,
Wysłano szczegóły jako pytanie tutaj.
Cade Roux,
-6

Po pierwsze, ciągi zerowe i zerowe nie zawsze były traktowane tak samo przez Oracle. Ciąg zerowy jest z definicji ciągiem niezawierającym znaków. To wcale nie jest to samo, co zero. NULL to z definicji brak danych.

Pięć lub sześć lat temu łańcuch zerowy traktowany był przez Oracle inaczej niż zerowy. Podczas gdy, podobnie jak null, łańcuch zerowy był równy wszystkim i różny od wszystkiego (co myślę, że jest w porządku dla null, ale całkowicie NIEPRAWIDŁOWY dla łańcucha zerowego), przynajmniej długość (łańcuch zerowy) zwróci 0, tak jak powinno, ponieważ łańcuch zerowy jest ciąg o zerowej długości.

Obecnie w Oracle długość (null) zwraca wartość null, która, jak sądzę, jest OK, ale długość (łańcuch null) również zwraca wartość null, co jest całkowicie NIEPRAWIDŁOWE.

Nie rozumiem, dlaczego postanowili zacząć traktować te 2 odrębne „wartości” tak samo. Oznaczają różne rzeczy, a programista powinien mieć możliwość działania na każdym z nich na różne sposoby. Fakt, że zmienili swoją metodologię, mówi mi, że tak naprawdę nie mają pojęcia, jak należy traktować te wartości.

Michael T. Gunderson
źródło
Wymagane jest cytowanie w celu rozróżnienia między „łańcuchem zerowym” a wartością NULL. W dowolnej bazie danych oprócz Oracle VARCHARpole może mieć wartość (zero lub więcej znaków) lub brak wartości (NULL), kropka.
„Pięć lub sześć lat temu” od 2011 r. Przypadałoby na 10 g (10.1 wydany w 2003 r., 10.2 w 2005 r.). 10g absolutnie nie wprowadziło żadnych globalnych zmian w obsłudze wartości zerowych i nigdy nie było żadnego rozróżnienia między NULLłańcuchem o wartości zerowej i takie rozróżnienie nie ma sensu. Obawiam się, że ta odpowiedź jest kompletną fantazją.
William Robertson