Zerowy (SQL) - Null (SQL)

Grecki mały znak omega (ω) jest używany do reprezentowania wartości Null w teorii baz danych .

Null lub NULL to specjalny znacznik używany w Structured Query Language do wskazania, że ​​wartość danych nie istnieje w bazie danych . Wprowadzony przez twórcę relacyjnego modelu bazy danych, EF Codd , SQL Null spełnia wymóg, aby wszystkie prawdziwe systemy zarządzania relacyjnymi bazami danych ( RDMS ) obsługiwały reprezentację „brakujących informacji i nieodpowiednich informacji”. Codd wprowadził również użycie małego greckiego symbolu omega (ω) do reprezentowania wartości Null w teorii baz danych . W SQL NULLjest zastrzeżonym słowem używanym do identyfikacji tego znacznika.

Nie należy mylić wartości null z wartością 0. Wartość null wskazuje na brak wartości, co nie jest tym samym, co wartość zero. Zastanówmy się na przykład nad pytaniem „Ile książek posiada Adam?” Odpowiedź może brzmieć „zero” ( wiemy, że nie posiada żadnego ) lub „null” ( nie wiemy, ile posiada). W tabeli bazy danych kolumna zawierająca tę odpowiedź zaczynałaby się bez wartości (oznaczona przez Null) i nie byłaby aktualizowana wartością „zero”, dopóki nie upewnimy się, że Adam nie posiada żadnych książek.

Wartość null SQL jest stanem, a nie wartością. To użycie jest zupełnie inne niż w większości języków programowania, gdzie null wartość referencji oznacza, że ​​nie wskazuje ona żadnego obiektu .

Historia

EF Codd wspomniał o zerach jako metodzie przedstawiania brakujących danych w modelu relacyjnym w pracy z 1975 r. w Biuletynie FDT ACM - SIGMOD . Artykuł Codda, który jest najczęściej cytowany w związku z semantyką Null (przyjętą w SQL) to jego artykuł z 1979 roku w ACM Transactions on Database Systems , w którym przedstawił również swój Relational Model/Tasmania , chociaż wiele innych propozycji z te ostatnie dokumenty pozostały niejasne. Sekcja 2.3 jego pracy z 1979 r. szczegółowo opisuje semantykę propagacji wartości zerowych w operacjach arytmetycznych, a także porównania wykorzystujące logikę trójwartościową (trójwartościową) podczas porównywania z wartościami zerowymi; szczegółowo opisuje również traktowanie wartości Nulls w innych operacjach na zestawach (ta ostatnia kwestia jest dziś nadal kontrowersyjna). W kręgach teorii baz danych pierwotna propozycja Codda (1975, 1979) jest obecnie określana jako „tabele Codda”. Codd później wzmocnił swoje wymaganie, aby wszystkie RDBMS wspierały wartość Null w celu wskazania brakujących danych w dwuczęściowym artykule opublikowanym w 1985 roku w magazynie ComputerWorld .

Standard SQL z 1986 roku w zasadzie przyjął propozycję Codda po prototypie implementacji w IBM System R . Chociaż Don Chamberlin uznał null (obok zduplikowanych wierszy) za jedną z najbardziej kontrowersyjnych cech SQL, bronił projektu Nulls in SQL, powołując się na pragmatyczne argumenty, że jest to najtańsza forma wsparcia systemowego dla brakujących informacji, oszczędzając programistę przed wiele zduplikowanych sprawdzeń na poziomie aplikacji (patrz problem z półpredykatem ) przy jednoczesnym zapewnieniu projektantowi bazy danych opcji nieużywania wartości Null, jeśli sobie tego życzą; na przykład w celu uniknięcia dobrze znanych anomalii (omówionych w sekcji semantyki tego artykułu). Chamberlin argumentował również, że poza zapewnieniem funkcjonalności brakujących wartości, praktyczne doświadczenie z wartościami Null doprowadziło również do innych funkcji języka, które opierają się na wartościach Null, takich jak pewne konstrukcje grupujące i sprzężenia zewnętrzne. Na koniec argumentował, że w praktyce wartości Null są również wykorzystywane jako szybki sposób na załatanie istniejącego schematu, gdy musi on ewoluować poza pierwotną intencję, kodując nie po to, by brakowało, ale raczej na nieodpowiednie informacje; na przykład baza danych, która szybko musi obsługiwać samochody elektryczne, mając jednocześnie kolumnę mil na galon.

Codd wskazał w swojej książce z 1990 r. The Relational Model for Database Management, Version 2, że pojedynczy znak Null wymagany przez standard SQL jest niewystarczający i powinien zostać zastąpiony dwoma oddzielnymi znacznikami typu Null, aby wskazać przyczynę braku danych. W książce Codda te dwa znaczniki typu Null są określane jako „Wartości A” i „Wartości I”, reprezentujące odpowiednio „brakujące, ale możliwe do zastosowania” i „brakujące, ale nie dające się zastosować”. Zalecenie Codda wymagałoby rozszerzenia systemu logicznego SQL tak, aby mógł pomieścić czterowartościowy system logiczny. Z powodu tej dodatkowej złożoności pomysł wielu wartości zerowych z różnymi definicjami nie zyskał powszechnej akceptacji w domenie praktyków baz danych. Pozostaje jednak aktywnym polem badań, z licznymi artykułami wciąż publikowanymi.

Wyzwania

Null był przedmiotem kontrowersji i był źródłem debaty ze względu na związaną z nim logikę trójwartościową (3VL), specjalne wymagania dotyczące jego użycia w złączeniach SQL oraz specjalną obsługę wymaganą przez funkcje agregujące i operatory grupowania SQL. Profesor informatyki Ron van der Meyden podsumował różne kwestie następująco: „Niespójności w standardzie SQL oznaczają, że nie jest możliwe przypisanie żadnej intuicyjnej semantyki logicznej traktowaniu wartości zerowych w SQL”. Chociaż pojawiły się różne propozycje rozwiązania tych problemów, złożoność alternatyw uniemożliwiła ich powszechne przyjęcie.

Propagacja zerowa

Działania arytmetyczne

Ponieważ Null nie jest wartością danych, ale znacznikiem nieobecnej wartości, użycie operatorów matematycznych na Null daje nieznany wynik, który jest reprezentowany przez Null. W poniższym przykładzie pomnożenie 10 przez wartość Null daje wartość Null:

10 * NULL          -- Result is NULL

Może to prowadzić do nieoczekiwanych rezultatów. Na przykład, gdy zostanie podjęta próba podzielenia wartości Null przez zero, platformy mogą zwrócić wartość Null zamiast zgłaszać oczekiwany „wyjątek danych – dzielenie przez zero”. Chociaż to zachowanie nie jest zdefiniowane przez standard ISO SQL, wielu dostawców DBMS traktuje tę operację podobnie. Na przykład platformy Oracle, PostgreSQL, MySQL Server i Microsoft SQL Server zwracają wynik Null dla następujących elementów:

NULL / 0

Łączenie ciągów

String konkatenacji operacje, które są powszechne w SQL prowadzić również w Null, gdy jeden z argumentów jest NULL. Poniższy przykład ilustruje wynik Null zwrócony przy użyciu wartości Null z ||operatorem łączenia ciągów SQL .

'Fish ' || NULL || 'Chips'   -- Result is NULL

Nie dotyczy to wszystkich implementacji baz danych. Na przykład w Oracle RDBMS NULL i pusty ciąg są uważane za to samo, a zatem 'Ryba' || NULL || „Frytki” daje w wyniku „Fryby rybne”.

Porównania z NULL i logiką trójwartościową (3VL)

Ponieważ Null nie należy do żadnej domeny danych , nie jest uważany za „wartość”, ale raczej za znacznik (lub symbol zastępczy) wskazujący niezdefiniowaną wartość . Z tego powodu porównania z wartością Null nigdy nie dają wyniku Prawda lub Fałsz, ale zawsze trzeci logiczny wynik, Nieznany. Logiczny wynik poniższego wyrażenia, które porównuje wartość 10 do Null, jest nieznany:

SELECT 10 = NULL       -- Results in Unknown

Jednak niektóre operacje na Null mogą zwracać wartości, jeśli brak wartości nie ma znaczenia dla wyniku operacji. Rozważmy następujący przykład:

SELECT NULL OR TRUE   -- Results in True

W tym przypadku fakt, że wartość po lewej stronie OR jest niepoznawalna, jest nieistotny, ponieważ wynik operacji OR byłby True niezależnie od wartości po lewej stronie.

SQL implementuje trzy logiczne wyniki, więc implementacje SQL muszą zapewniać wyspecjalizowaną logikę trójwartościową (3VL) . Reguły rządzące trójwartościową logiką SQL są pokazane w poniższych tabelach ( p i q reprezentują stany logiczne) " Tabele prawdy używane przez SQL dla AND, OR i NOT odpowiadają wspólnemu fragmentowi trójwartościowej logiki Kleene'a i Łukasiewicza ( które różnią się definicją implikacji, jednak SQL nie definiuje takiej operacji).

P Q p LUB q p AND q p = q
Prawdziwe Prawdziwe Prawdziwe Prawdziwe Prawdziwe
Prawdziwe Fałszywe Prawdziwe Fałszywe Fałszywe
Prawdziwe Nieznany Prawdziwe Nieznany Nieznany
Fałszywe Prawdziwe Prawdziwe Fałszywe Fałszywe
Fałszywe Fałszywe Fałszywe Fałszywe Prawdziwe
Fałszywe Nieznany Nieznany Fałszywe Nieznany
Nieznany Prawdziwe Prawdziwe Nieznany Nieznany
Nieznany Fałszywe Nieznany Fałszywe Nieznany
Nieznany Nieznany Nieznany Nieznany Nieznany
P NIE p
Prawdziwe Fałszywe
Fałszywe Prawdziwe
Nieznany Nieznany

Efekt klauzuli Nieznane w WHERE

Trójwartościowa logika SQL występuje w języku manipulacji danymi (DML) w predykatach porównania instrukcji i zapytań DML. WHEREKlauzula powoduje oświadczenie DML do działania na tylko te wiersze, dla których predykat wartość true. Wiersze dla którego predykat Zwraca ono nieprawdziwe lub nieznanym nie działały przez INSERT, UPDATElub DELETEinstrukcji DML i są odrzucane przez SELECTzapytaniami. Interpretowanie nieznanych i fałszywych jako tego samego wyniku logicznego jest częstym błędem napotykanym podczas pracy z wartościami Null. Poniższy prosty przykład demonstruje ten błąd:

SELECT *
FROM t
WHERE i = NULL;

Przykładowe zapytanie powyżej logicznie zawsze zwraca zero wierszy, ponieważ porównanie kolumny i z wartością Null zawsze zwraca wartość Unknown, nawet dla tych wierszy, w których i ma wartość Null. Nieznany wynik powoduje, że SELECTinstrukcja sumarycznie odrzuca każdy wiersz. (Jednak w praktyce niektóre narzędzia SQL będą pobierać wiersze przy użyciu porównania z wartością Null.)

Predykaty porównawcze specyficzne dla null i specyficzne dla 3VL

Podstawowe operatory porównania SQL zawsze zwracają Unknown podczas porównywania czegokolwiek z wartością Null, więc standard SQL przewiduje dwa specjalne predykaty porównania specyficzne dla wartości Null. Te IS NULLi IS NOT NULLorzeczniki (wykorzystujące postfix składni) sprawdzania, czy dane, czy nie jest zerowy.

Standard SQL zawiera opcjonalną funkcję F571 „Testy wartości prawdy”, która wprowadza trzy dodatkowe logiczne operatory jednoargumentowe (w rzeczywistości sześć, jeśli policzymy ich negację, która jest częścią ich składni), również przy użyciu notacji postfiksowej. Mają następujące tabele prawdy:

P p TO PRAWDA p NIE JEST PRAWDA p JEST FAŁSZ p NIE JEST FAŁSZYWE p JEST NIEZNANE p NIE JEST NIEZNANE
Prawdziwe Prawdziwe Fałszywe Fałszywe Prawdziwe Fałszywe Prawdziwe
Fałszywe Fałszywe Prawdziwe Prawdziwe Fałszywe Fałszywe Prawdziwe
Nieznany Fałszywe Prawdziwe Fałszywe Prawdziwe Prawdziwe Fałszywe

Funkcja F571 jest ortogonalna do obecności typu danych binarnych w SQL (omówione w dalszej części tego artykułu) i pomimo podobieństw składniowych F571 nie wprowadza do języka literałów logicznych lub trójwartościowych . Funkcja F571 była faktycznie obecna w SQL92 , na długo przed wprowadzeniem typu danych binarnych do standardu w 1999 roku. Funkcja F571 jest jednak zaimplementowana przez kilka systemów; PostgreSQL jest jednym z tych, którzy go implementują.

Dodanie IS UNKNOWN do innych operatorów trójwartościowej logiki SQL sprawia, że ​​trójwartościowa logika SQL staje się funkcjonalnie kompletna , co oznacza, że ​​jej operatory logiczne mogą wyrażać (w połączeniu) dowolną możliwą trójwartościową funkcję logiczną.

W systemach, które nie obsługują funkcji F571, można emulować IS UNKNOWN p , przeglądając każdy argument, który może spowodować, że wyrażenie p jest nieznane i testując te argumenty za pomocą IS NULL lub innych funkcji specyficznych dla NULL, chociaż może to być bardziej nieporęczny.

Prawo wykluczonej czwartej (w klauzulach WHERE)

W trójwartościowej logice SQL prawo wykluczonego środka , p OR NOT p , nie jest już prawdziwe dla wszystkich p . Dokładniej, w trójwartościowej logice SQL p OR NOT p jest nieznane dokładnie wtedy, gdy p jest nieznane, a w przeciwnym razie prawdziwe. Ponieważ bezpośrednie porównania z wartością Null dają nieznaną wartość logiczną, następujące zapytanie

SELECT * FROM stuff WHERE ( x = 10 ) OR NOT ( x = 10 );

nie jest równoważne w SQL z

SELECT * FROM stuff;

jeśli kolumna x zawiera jakiekolwiek wartości null; w takim przypadku drugie zapytanie zwróciłoby kilka wierszy, których nie zwraca pierwsze, a mianowicie wszystkie te, w których x jest Null. W klasycznej logice dwuwartościowej prawo wyłączonego środka pozwalałoby na uproszczenie predykatu WHERE, a właściwie jego eliminację. Próba zastosowania prawa wykluczonego środka do 3VL SQL jest w rzeczywistości fałszywą dychotomią . Drugie zapytanie jest właściwie równoważne z:

SELECT * FROM stuff;
-- is (because of 3VL) equivalent to:
SELECT * FROM stuff WHERE ( x = 10 ) OR NOT ( x = 10 ) OR x IS NULL;

Zatem poprawne uproszczenie pierwszej instrukcji w SQL wymaga zwrócenia wszystkich wierszy, w których x nie jest puste.

SELECT * FROM stuff WHERE x IS NOT NULL;

W związku z powyższym zauważ, że dla klauzuli WHERE języka SQL można zapisać tautologię podobną do prawa wykluczonego środka. Zakładając, że operator IS UNKNOWN jest obecny, p OR (NOT p ) OR ( p IS UNKNOWN) jest prawdziwe dla każdego predykatu p . Wśród logików nazywa się to prawem wykluczenia czwartego .

Istnieje kilka wyrażeń SQL, w których mniej oczywiste jest, gdzie pojawia się fałszywy dylemat, na przykład:

SELECT 'ok' WHERE 1 NOT IN (SELECT CAST (NULL AS INTEGER))
UNION
SELECT 'ok' WHERE 1 IN (SELECT CAST (NULL AS INTEGER));

nie generuje wierszy, ponieważ INprzekłada się na iterowaną wersję równości względem zestawu argumentów, a 1<>NULL jest nieznane, podobnie jak 1=NULL jest nieznane. (CAST w tym przykładzie jest potrzebny tylko w niektórych implementacjach SQL, takich jak PostgreSQL, które w przeciwnym razie odrzuciłyby go z błędem sprawdzania typu. W wielu systemach w podzapytaniu działa zwykły SELECT NULL.) Brakujący przypadek powyżej to oczywiście:

SELECT 'ok' WHERE (1 IN (SELECT CAST (NULL AS INTEGER))) IS UNKNOWN;

Wpływ wartości Null i Unknown w innych konstruktach

Łączy

Sprzężenia oceniają przy użyciu tych samych reguł porównania, co w przypadku klauzul WHERE. Dlatego należy zachować ostrożność podczas używania kolumn dopuszczających wartość null w kryteriach sprzężenia SQL. W szczególności tabela zawierająca wartości null nie jest równa naturalnemu sprzężeniu własnemu, co oznacza, że ​​podczas gdy jest to prawdą dla każdej relacji R w algebrze relacyjnej , samosprzężenie SQL wykluczy wszystkie wiersze mające gdziekolwiek wartość null. Przykład takiego zachowania podano w sekcji poświęconej analizie semantyki braków danych wartości Nulls.

COALESCEFunkcji lub CASEwyrażeń SQL można użyć do „symulowania” równości wartości Null w kryteriach łączenia, IS NULLa IS NOT NULLpredykaty i mogą być również używane w kryteriach łączenia. Poniższy predykat sprawdza równość wartości A i B i traktuje wartości Nulls jako równe.

(A = B) OR (A IS NULL AND B IS NULL)

Wyrażenia CASE

SQL udostępnia dwa rodzaje wyrażeń warunkowych . Jedna z nich nazywa się "prostym PRZYPADKIEM" i działa jak instrukcja switch . Druga nazywa się w standardzie "przeszukiwanym CASE" i działa jak if...elseif .

Proste CASEwyrażenia używają niejawnych porównań równości, które działają zgodnie z tymi samymi regułami, co WHEREreguły klauzul DML dla wartości Null. Tak więc proste CASEwyrażenie nie może bezpośrednio sprawdzić istnienia wartości Null. Sprawdzenie wartości Null w prostym CASEwyrażeniu zawsze daje w wyniku Unknown, jak poniżej:

SELECT CASE i WHEN NULL THEN 'Is Null'  -- This will never be returned
              WHEN    0 THEN 'Is Zero'  -- This will be returned when i = 0
              WHEN    1 THEN 'Is One'   -- This will be returned when i = 1
              END
FROM t;

Ponieważ wyrażenie ma i = NULLwartość Unknown bez względu na to, co zawiera kolumna wartości i (nawet jeśli zawiera wartość Null), ciąg 'Is Null'nigdy nie zostanie zwrócony.

Z drugiej strony „wyszukiwane” CASEwyrażenie może używać predykatów takich jak IS NULLiw IS NOT NULLswoich warunkach. Poniższy przykład pokazuje, jak używać wyszukiwanego CASEwyrażenia, aby poprawnie sprawdzić, czy nie ma wartości Null:

SELECT CASE WHEN i IS NULL THEN 'Null Result'  -- This will be returned when i is NULL
            WHEN     i = 0 THEN 'Zero'         -- This will be returned when i = 0
            WHEN     i = 1 THEN 'One'          -- This will be returned when i = 1
            END
FROM t;

W wyszukiwanym CASEwyrażeniu ciąg 'Null Result'jest zwracany dla wszystkich wierszy, w których i ma wartość Null.

Dialekt SQL Oracle zapewnia wbudowaną funkcję, DECODEktóra może być używana zamiast prostych wyrażeń CASE i uważa, że ​​dwie wartości null są równe.

SELECT DECODE(i, NULL, 'Null Result', 0, 'Zero', 1, 'One') FROM t;

Na koniec wszystkie te konstrukcje zwracają wartość NULL, jeśli nie znaleziono dopasowania; mają ELSE NULLklauzulę default .

Oświadczenia IF w rozszerzeniach proceduralnych

SQL/PSM (SQL Persistent Stored Modules) definiuje rozszerzenia proceduralne dla SQL, takie jak IFinstrukcja. Jednak główni dostawcy SQL historycznie uwzględniali własne, zastrzeżone rozszerzenia proceduralne. Rozszerzenia proceduralne dotyczące pętli i porównań działają zgodnie z regułami porównywania wartości Null, podobnie jak w przypadku instrukcji i zapytań DML. Poniższy fragment kodu, w standardowym formacie ISO SQL, demonstruje użycie wartości Null 3VL w IFinstrukcji.

IF i = NULL THEN
      SELECT 'Result is True'
ELSEIF NOT(i = NULL) THEN
      SELECT 'Result is False'
ELSE
      SELECT 'Result is Unknown';

Do IFrachunku wykonuje czynności wyłącznie dla tych porównań, które oceniają true. W przypadku instrukcji, które mają wartość False lub Unknown, IFinstrukcja przekazuje kontrolę do ELSEIFklauzuli, a na końcu do ELSEklauzuli. Wynikiem powyższego kodu zawsze będzie komunikat, 'Result is Unknown'ponieważ porównania z wartością Null zawsze dają wartość Unknown.

Analiza semantyki brakujących wartości SQL Null

Przełomowa praca T. Imielińskiego i W. Lipskiego Jr. (1984) dostarczyła ram do oceny zamierzonej semantyki różnych propozycji implementacji semantyki brakującej wartości, która jest określana jako Algebry Imielińskiego-Lipskiego . Ta sekcja z grubsza podąża za rozdziałem 19 podręcznika „Alice”. Podobna prezentacja pojawia się w recenzji Ron van der Meyden, §10.4.

W selekcjach i projekcjach: słaba reprezentacja

Konstrukcje reprezentujące brakujące informacje, takie jak tabele Codd, są w rzeczywistości przeznaczone do reprezentowania zestawu relacji, po jednej dla każdego możliwego wystąpienia ich parametrów; w przypadku tabel Codd oznacza to zastąpienie wartości Null pewną konkretną wartością. Na przykład,

 

Emp
Nazwa Wiek
Jerzy 43
Harriet NULL
Karol 56
EmpH22
Nazwa Wiek
Jerzy 43
Harriet 22
Karol 56
EmpH37
Nazwa Wiek
Jerzy 43
Harriet 37
Karol 56
Tabela Codd Emp może reprezentować relację EmpH22 lub EmpH37 , jak pokazano na rysunku.

Konstrukt (taki jak tabela Codda) jest uważany za system silnej reprezentacji (brakujących informacji), jeśli jakakolwiek odpowiedź na zapytanie zadane na konstrukcie może być uszczegółowiona w celu uzyskania odpowiedzi na każde odpowiadające zapytanie dotyczące relacji, które reprezentuje, co są postrzegane jako modele konstrukcji. Dokładniej, jeśli q jest formułą zapytania w algebrze relacyjnej (o „czystych” relacjach) i jeśli q jest jej podniesieniem do konstrukcji mającej reprezentować brakujące informacje, silna reprezentacja ma tę właściwość, że dla dowolnego zapytania q i (tabela) konstrukt T , q podnosi wszystkie odpowiedzi do konstruktu, tj.:

(Powyższe musi obowiązywać w przypadku zapytań przyjmujących dowolną liczbę tabel jako argumenty, ale ograniczenie do jednej tabeli wystarcza w tej dyskusji.) Oczywiście tabele Codd nie mają tej silnej właściwości, jeśli selekcje i projekcje są uważane za część języka zapytań. Na przykład wszystkie odpowiedzi na:

SELECT * FROM Emp WHERE Age = 22;

powinna zawierać możliwość istnienia relacji takiej jak EmpH22. Jednak tabele Codd nie mogą reprezentować alternatywy „wynik z możliwym 0 lub 1 wierszem”. Urządzenie, głównie teoretyczne, zwane tabelą warunkową (lub tabelą c) może jednak reprezentować taką odpowiedź:

Wynik
Nazwa Wiek stan: schorzenie
Harriet ω 1 ω 1 = 22

gdzie kolumna warunku jest interpretowana jako wiersz nie istnieje, jeśli warunek jest fałszywy. Okazuje się, że ponieważ formuły w kolumnie warunku c-tablicy mogą być dowolnymi formułami logiki zdań , algorytm rozwiązywania problemu, czy c-tablica reprezentuje jakąś konkretną relację, ma złożoność współ-NP-zupełną , a zatem jest mało praktyczna wartość.

Pożądane jest zatem słabsze pojęcie reprezentacji. Imieliński i Lipski wprowadzili pojęcie słabej reprezentacji , które zasadniczo pozwala (podniesionym) zapytaniom o konstrukt zwrócić reprezentację tylko dla pewnych informacji, tj. czy jest ona prawidłowa dla wszystkich instancji (modeli) konstruktu „ świata możliwego ”. Konkretnie, konstrukcja jest słabym systemem reprezentacji, jeśli

Prawa strona powyższego równania to pewna informacja, czyli informacja, którą z pewnością można wydobyć z bazy danych niezależnie od tego, jakie wartości zostaną użyte do zastąpienia wartości Null w bazie danych. W przykładzie, który rozważaliśmy powyżej, łatwo zauważyć, że przecięcie wszystkich możliwych modeli (tj. pewnych informacji) wyboru zapytania jest w rzeczywistości puste, ponieważ na przykład zapytanie (niepodniesione) nie zwraca żadnych wierszy dla relacji EmpH37. Mówiąc bardziej ogólnie, Imieliński i Lipski wykazali, że tabele Codd są słabym systemem reprezentacji, jeśli język zapytań ogranicza się do projekcji, selekcji (i zmiany nazw kolumn). Jednak, gdy tylko dodamy do języka zapytań złączenia lub unię, nawet ta słaba właściwość zostanie utracona, jak pokazano w następnej sekcji. WHERE Age = 22

Jeśli brane są pod uwagę łączenia lub związki: nawet słaba reprezentacja

Rozważ następujące zapytanie dotyczące tej samej tabeli Codd Emp z poprzedniej sekcji:

SELECT Name FROM Emp WHERE Age = 22
UNION
SELECT Name FROM Emp WHERE Age <> 22;

Jakakolwiek konkretna wartość zostałaby wybrana dla NULLwieku Harriet, powyższe zapytanie zwróci pełną kolumnę nazw dowolnego modelu Emp , ale gdy (podniesione) zapytanie zostanie uruchomione na samym Emp , Harriet zawsze będzie brakować, tj. mamy :

Wynik zapytania na Emp :
Nazwa
Jerzy
Karol
Wynik zapytania na dowolnym modelu Emp :
Nazwa
Jerzy
Harriet
Karol

Tak więc, gdy do języka zapytań dodawane są unie, tabele Codd nie są nawet słabym systemem reprezentacji brakujących informacji, co oznacza, że ​​zapytania nad nimi nie przekazują nawet wszystkich pewnych informacji. Należy tutaj zauważyć, że semantyka UNION on Nulls, o której mowa w dalszej części, nawet nie wchodziła w grę w tym zapytaniu. „Zapominajki” charakter dwóch podzapytań wystarczył, aby zagwarantować, że niektóre pewne informacje nie zostaną zgłoszone, gdy powyższe zapytanie zostanie uruchomione w tabeli Codd Emp.

W przypadku sprzężeń naturalnych przykład potrzebny do pokazania, że ​​pewne informacje mogą nie zostać zgłoszone przez niektóre zapytania, jest nieco bardziej skomplikowany. Rozważ stół

J
F1 F2 F3
11 NULL 13
21 NULL 23
31 32 33

i zapytanie

SELECT F1, F3 FROM
  (SELECT F1, F2 FROM J) AS F12
  NATURAL JOIN
  (SELECT F2, F3 FROM J) AS F23;
Wynik zapytania na J:
F1 F3
31 33
Wynik zapytania na dowolnym modelu J:
F1 F3
11 13
21 23
31 33

Intuicja co do tego, co dzieje się powyżej, jest taka, że ​​tabele Codd reprezentujące prognozy w podzapytaniach tracą świadomość faktu, że wartości Null w kolumnach F12.F2 i F23.F2 są w rzeczywistości kopiami oryginałów w tabeli J. Ta obserwacja sugeruje, że stosunkowo prostym ulepszeniem tabel Codd (które działa poprawnie w tym przykładzie) byłoby użycie stałych Skolem (czyli funkcji Skolem, które są również funkcjami stałymi ), powiedzmy ω 12 i ω 22 zamiast pojedynczego symbolu NULL. Takie podejście, zwane tabelami v lub tabelami naiwnymi, jest mniej kosztowne obliczeniowo niż omówione powyżej tabele c. Jednak nadal nie jest to kompletne rozwiązanie dla niekompletnych informacji w tym sensie, że v-tabele są tylko słabą reprezentacją dla zapytań nie używających żadnych negacji w selekcji (i nie używających również żadnej różnicy zbiorów). Pierwszym przykładem rozważanym w tej sekcji jest użycie klauzuli negatywnej selekcji , więc jest to również przykład, w którym zapytania v-tabeli nie zgłaszają pewnych informacji. WHERE Age <> 22

Sprawdź ograniczenia i klucze obce

Podstawowym miejscem, w którym trójwartościowa logika SQL przecina się z językiem DDL ( SQL Data Definition Language ), jest forma ograniczeń sprawdzających . Ograniczenie sprawdzające umieszczone na kolumnie działa według nieco innego zestawu reguł niż te dla WHEREklauzuli DML . Podczas gdy WHEREklauzula DML musi mieć wartość True dla wiersza, ograniczenie sprawdzające nie może mieć wartości False. (Z perspektywy logicznej wyznaczonymi wartościami są Prawda i Nieznane). Oznacza to, że ograniczenie sprawdzające powiedzie się, jeśli wynikiem sprawdzenia będzie Prawda lub Nieznane. Poniższa przykładowa tabela z ograniczeniem sprawdzania zabroni wstawiania dowolnych wartości całkowitych do kolumny i , ale pozwoli na wstawienie wartości Null, ponieważ wynik sprawdzenia będzie zawsze oceniany jako Unknown for Nulls.

CREATE TABLE t (
     i INTEGER,
     CONSTRAINT ck_i CHECK ( i < 0 AND i = 0 AND i > 0 ) );

Ze względu na zmianę wyznaczonych wartości względem klauzuli WHERE , z punktu widzenia logiki, prawo wyłączonego środka jest tautologią ograniczeń CHECK , co oznacza, że zawsze się udaje. Co więcej, zakładając, że wartości Null mają być interpretowane jako istniejące, ale nieznane wartości, niektóre patologiczne KONTROLE, takie jak powyższa, umożliwiają wstawianie wartości Null, których nigdy nie można zastąpić żadną wartością inną niż null. CHECK (p OR NOT p)

Aby ograniczyć kolumnę do odrzucania wartości Null, NOT NULLmożna zastosować ograniczenie, jak pokazano w poniższym przykładzie. NOT NULLOgraniczeniem jest semantycznie równoważne ograniczenie wyboru z IS NOT NULLorzecznika.

CREATE TABLE t ( i INTEGER NOT NULL );

Domyślnie ograniczenia sprawdzania kluczy obcych odnoszą sukces, jeśli którekolwiek z pól w takich kluczach ma wartość Null. Na przykład stół

CREATE TABLE Books
( title VARCHAR(100),
  author_last VARCHAR(20),
  author_first VARCHAR(20),
FOREIGN KEY (author_last, author_first)
  REFERENCES Authors(last_name, first_name));

pozwoliłoby na wstawianie wierszy, w których autor_last lub autor_pierwszy są NULLniezależnie od tego, jak zdefiniowano autorów tabeli lub co ona zawiera. Dokładniej, null w którymkolwiek z tych pól pozwalałby na dowolną wartość w drugim, nawet jeśli nie ma go w tabeli Authors. Na przykład, jeśli autorzy zawierali tylko ('Doe', 'John'), ('Smith', NULL)spełniłoby to ograniczenie klucza obcego. SQL-92 dodał dwie dodatkowe opcje zawężania dopasowań w takich przypadkach. Jeśli MATCH PARTIALzostanie dodany po REFERENCESdeklaracji, to każdy inny niż null musi pasować do klucza obcego, np. ('Doe', NULL)nadal będzie pasował, ale ('Smith', NULL)nie będzie pasował . Wreszcie, jeśli MATCH FULLzostanie dodany, to ('Smith', NULL)również nie będzie pasował do ograniczenia, ale (NULL, NULL)nadal będzie pasował.

Połączenia zewnętrzne

Przykładowe zapytanie SQL ze sprzężeniem zewnętrznym z symbolami zastępczymi o wartości Null w zestawie wyników. Markery Null są reprezentowane przez słowo NULLzamiast danych w wynikach. Wyniki pochodzą z Microsoft SQL Server , jak pokazano w SQL Server Management Studio.

Zewnętrzne sprzężenia SQL , w tym lewe sprzężenia zewnętrzne, prawe sprzężenia zewnętrzne i pełne sprzężenia zewnętrzne, automatycznie generują wartości Null jako symbole zastępcze brakujących wartości w powiązanych tabelach. Na przykład dla lewych sprzężeń zewnętrznych wartości Null są tworzone w miejscu brakujących wierszy w tabeli znajdujących się po prawej stronie LEFT OUTER JOINoperatora. Poniższy prosty przykład używa dwóch tabel do zademonstrowania produkcji zastępczej wartości Null w lewym sprzężeniu zewnętrznym.

Pierwsza tabela ( Employee ) zawiera numery i nazwiska pracowników, natomiast druga tabela ( PhoneNumber ) zawiera powiązane numery ID pracowników i numery telefonów , jak pokazano poniżej.

Pracownik
NS Nazwisko Imię
1 Johnson Joe
2 Chwytak Larry
3 Thompson Tomasz
4 Patterson Patrycja
Numer telefonu
NS Numer
1 555-2323
3 555-9876

Poniższe przykładowe zapytanie SQL wykonuje lewe sprzężenie zewnętrzne w tych dwóch tabelach.

SELECT e.ID, e.LastName, e.FirstName, pn.Number
FROM Employee e
LEFT OUTER JOIN PhoneNumber pn
ON e.ID = pn.ID;

Zestaw wyników wygenerowany przez to zapytanie pokazuje, w jaki sposób SQL używa wartości Null jako symbolu zastępczego dla wartości brakujących w tabeli po prawej stronie ( PhoneNumber ), jak pokazano poniżej.

Wynik zapytania
NS Nazwisko Imię Numer
1 Johnson Joe 555-2323
2 Chwytak Larry NULL
3 Thompson Tomasz 555-9876
4 Patterson Patrycja NULL

Funkcje agregujące

SQL definiuje funkcje agregujące, aby uprościć obliczenia agregujące po stronie serwera na danych. Z wyjątkiem COUNT(*)funkcji wszystkie funkcje agregujące wykonują krok eliminacji wartości NULL, dzięki czemu wartości null nie są uwzględniane w końcowym wyniku obliczeń.

Zauważ, że eliminacja Null nie jest równoznaczna z zastąpieniem Null zerem. Na przykład w poniższej tabeli AVG(i)(średnia wartości i) da inny wynik niż AVG(j):

i J
150 150
200 200
250 250
NULL 0

Oto AVG(i)200 (średnia 150, 200 i 250), a AVG(j)150 (średnia 150, 200, 250 i 0). Dobrze znanym skutkiem ubocznym tego jest to, że w SQL AVG(z)jest to odpowiednik not SUM(z)/COUNT(*)ale SUM(z)/COUNT(z).

Dane wyjściowe funkcji agregującej również mogą mieć wartość Null. Oto przykład:

SELECT COUNT(*), MIN(e.Wage), MAX(e.Wage)
FROM Employee e
WHERE e.LastName LIKE '%Jones%';

To zapytanie zawsze wygeneruje dokładnie jeden wiersz, zliczając liczbę pracowników, których nazwisko zawiera „Jones” i podając minimalną i maksymalną płacę znalezioną dla tych pracowników. Co się jednak stanie, jeśli żaden z pracowników nie spełni podanych kryteriów? Obliczenie minimalnej lub maksymalnej wartości pustego zestawu jest niemożliwe, więc te wyniki muszą być NULL, co oznacza brak odpowiedzi. Nie jest to wartość nieznana, jest to wartość Null reprezentująca brak wartości. Wynik byłby następujący:

LICZYĆ(*) MIN(e.Płaca) MAX(e.Płaca)
0 NULL NULL

Gdy dwie wartości null są równe: grupowanie, sortowanie i niektóre operacje na zbiorach

Ponieważ SQL:2003 definiuje wszystkie znaczniki Null jako nierówne sobie, wymagana była specjalna definicja w celu grupowania wartości Null podczas wykonywania pewnych operacji. SQL definiuje „dowolne dwie wartości, które są sobie równe, lub dowolne dwie wartości Null”, jako „nie różniące się”. Ta definicja nie odrębny pozwala SQL do grupowania i sortowania wartości null, gdy GROUP BYklauzula (i inne słowa kluczowe, które wykonują grupy) są stosowane.

Inne operacje SQL, klauzule i słowa kluczowe używają "not differ" w traktowaniu wartości Null. Należą do nich:

  • PARTITION BY klauzula funkcji rankingowych i okienkowych, takich jak ROW_NUMBER
  • UNION, INTERSECT, i EXCEPToperator, które traktują wartości NULL jako takie same dla celów porównywania/eliminowania wierszy
  • DISTINCTsłowo kluczowe używane w SELECTzapytaniach

Zasada, że ​​wartości null nie są sobie równe (ale wynik jest nieznany) jest skutecznie naruszana w specyfikacji SQL dla UNIONoperatora, która identyfikuje ze sobą wartości null. W konsekwencji niektóre operacje na zbiorach w SQL, takie jak suma lub różnica, mogą dawać wyniki nie reprezentujące pewnych informacji, w przeciwieństwie do operacji obejmujących jawne porównania z wartością NULL (np. te w WHEREklauzuli omówionej powyżej). W propozycji Codda z 1979 r. (która została zasadniczo przyjęta przez SQL92) ta niespójność semantyczna jest racjonalizowana przez argument, że usuwanie duplikatów w operacjach na zbiorach odbywa się „na niższym poziomie szczegółowości niż testowanie równości w ocenie operacji pobierania”.

Standard SQL nie definiuje jawnie domyślnej kolejności sortowania dla wartości Null. Zamiast tego w systemach zgodnych wartości Null mogą być sortowane przed lub po wszystkich wartościach danych, odpowiednio za pomocą klauzul NULLS FIRSTlub listy. Jednak nie wszyscy dostawcy DBMS implementują tę funkcjonalność. Sprzedawcy, którzy nie implementują tej funkcjonalności, mogą określić różne traktowanie sortowania zerowego w DBMS. NULLS LASTORDER BY

Wpływ na działanie indeksu

Niektóre produkty SQL nie indeksują kluczy zawierających wartości NULL. Na przykład wersje PostgreSQL przed 8.3 nie, a dokumentacja indeksu B-drzewa stwierdza, że:

B-drzewa mogą obsługiwać zapytania dotyczące równości i zakresu na danych, które można posortować według pewnej kolejności. W szczególności, planer zapytań PostgreSQL rozważy użycie indeksu B-drzewa za każdym razem, gdy indeksowana kolumna jest zaangażowana w porównanie przy użyciu jednego z tych operatorów: < ≤ = ≥ >

Konstrukcje równoważne kombinacjom tych operatorów, takie jak BETWEEN i IN, mogą być również zaimplementowane z przeszukiwaniem indeksu B-drzewa. (Pamiętaj jednak, że IS NULL nie jest równoważne z = i nie można go indeksować).

W przypadkach, gdy indeks wymusza unikalność, wartości NULL są wykluczane z indeksu, a unikatowość nie jest wymuszana między wartościami NULL. Ponownie, cytuję z dokumentacji PostgreSQL :

Gdy indeks jest zadeklarowany jako unikatowy, wiele wierszy tabeli o równych indeksowanych wartościach nie będzie dozwolonych. Nulls nie są uważane za równe. Unikalny indeks wielokolumnowy odrzuci tylko przypadki, w których wszystkie indeksowane kolumny są równe w dwóch wierszach.

Jest to zgodne ze zdefiniowanym w SQL:2003 zachowaniem skalarnych porównań zerowych.

Innym sposobem indeksowania null polega ich obsługi, jak nie odrębny zgodnie z SQL: 2003 zdefiniowanego zachowania. Na przykład dokumentacja Microsoft SQL Server stwierdza, co następuje:

Do celów indeksowania wartości NULL są porównywane jako równe. Dlatego nie można utworzyć indeksu unikatowego lub ograniczenia UNIQUE, jeśli klucze mają wartość NULL w więcej niż jednym wierszu. Wybierz kolumny, które są zdefiniowane jako NOT NULL, gdy wybrano kolumny dla indeksu unikatowego lub ograniczenia unikatowego.

Obie te strategie indeksowania są zgodne ze zdefiniowanym w SQL:2003 zachowaniem wartości Null. Ponieważ metodologie indeksowania nie są wyraźnie zdefiniowane przez standard SQL:2003, strategie indeksowania dla wartości Null są całkowicie pozostawione dostawcom do zaprojektowania i wdrożenia.

Funkcje obsługi zerowej

SQL definiuje dwie funkcje do jawnej obsługi wartości Null: NULLIFi COALESCE. Obie funkcje są skrótami dla wyszukiwanych CASEwyrażeń .

NULLIF

NULLIFFunkcja dwa parametry. Jeśli pierwszy parametr jest równy drugiemu parametrowi, NULLIFzwraca wartość Null. W przeciwnym razie zwracana jest wartość pierwszego parametru.

NULLIF(value1, value2)

Tak więc NULLIFjest skrótem następującego CASEwyrażenia:

CASE WHEN value1 = value2 THEN NULL ELSE value1 END

ŁĄCZYĆ

COALESCEFunkcja przyjmuje listę parametrów zawracania pierwszej wartości nie-zerową z listy:

COALESCE(value1, value2, value3, ...)

COALESCEjest zdefiniowany jako skrót dla następującego CASEwyrażenia SQL :

CASE WHEN value1 IS NOT NULL THEN value1
     WHEN value2 IS NOT NULL THEN value2
     WHEN value3 IS NOT NULL THEN value3
     ...
     END

Niektóre DBMS SQL implementują funkcje specyficzne dla dostawcy, podobne do COALESCE. Niektóre systemy (np. Transact-SQL ) implementują ISNULLfunkcję lub inne podobne funkcje, które są funkcjonalnie podobne do COALESCE. (Zobacz Isfunkcje, aby uzyskać więcej informacji na temat ISfunkcji w Transact-SQL).

NVL

Funkcja Oracle NVLprzyjmuje dwa parametry. Zwraca pierwszy parametr inny niż NULL lub NULL, jeśli wszystkie parametry mają wartość NULL.

COALESCEEkspresja może być przekształcony w równoważnej NVLekspresji w sposób następujący:

COALESCE ( val1, ... , val{n} )

przemienia się w:

NVL( val1 , NVL( val2 , NVL( val3 ,  , NVL ( val{n-1} , val{n} )  )))

Przypadkiem użycia tej funkcji jest zastąpienie w wyrażeniu NULL wartością, np. NVL(SALARY, 0)„jeśli SALARYjest NULL, zastąp ją wartością 0”.

Jest jednak jeden godny uwagi wyjątek. W większości implementacji COALESCEocenia swoje parametry, dopóki nie osiągnie pierwszego innego niż NULL, podczas gdy NVLocenia wszystkie swoje parametry. Jest to ważne z kilku powodów. Parametr po pierwszym parametrze innym niż NULL może być funkcją, która może być kosztowna obliczeniowo, nieprawidłowa lub może powodować nieoczekiwane skutki uboczne.

Wpisywanie danych Null i Unknown

NULL Dosłowny jest bez typu SQL, co oznacza, że nie jest on oznaczony jako całkowitą, charakter, lub jakiegokolwiek innego specyficzny typ danych . Z tego powodu czasami jest obowiązkowe (lub pożądane) jawne przekonwertowanie wartości Null na określony typ danych. Na przykład, jeśli przeciążone funkcje są obsługiwane przez RDBMS, SQL może nie być w stanie automatycznie przetłumaczyć na właściwą funkcję bez znajomości typów danych wszystkich parametrów, w tym tych, dla których przekazano wartość Null.

Konwersja z NULLliterału na Null określonego typu jest możliwa przy użyciu CASTwprowadzonego w SQL-92 . Na przykład:

CAST (NULL AS INTEGER)

reprezentuje nieobecną wartość typu INTEGER.

Rzeczywiste wpisywanie Unknown (różne lub nie od samego NULL) różni się w zależności od implementacji SQL. Na przykład następujące

SELECT 'ok' WHERE (NULL <> 1) IS NULL;

parsuje i wykonuje się pomyślnie w niektórych środowiskach (np. SQLite lub PostgreSQL ), które ujednolicają wartość logiczną NULL z Unknown, ale nie są w stanie przeanalizować w innych (np. w SQL Server Compact ). MySQL zachowuje się pod tym względem podobnie do PostgreSQL (z drobnym wyjątkiem, że MySQL traktuje TRUE i FALSE jako nie różniące się od zwykłych liczb całkowitych 1 i 0). PostgreSQL dodatkowo implementuje IS UNKNOWNpredykat, którego można użyć do sprawdzenia, czy trzywartościowy wynik logiczny jest nieznany, chociaż jest to tylko cukier składniowy.

typ danych BOOLEAN

Standard ISO SQL:1999 wprowadził typ danych BOOLEAN do SQL, jednak nadal jest to tylko opcjonalna, niepodstawowa funkcja, o kodzie T031.

Gdy jest ograniczony przez NOT NULLograniczenie, SQL BOOLEAN działa jak typ Boolean z innych języków. Jednak bez ograniczeń typ danych BOOLEAN, pomimo swojej nazwy, może zawierać wartości prawdy PRAWDA, FAŁSZ i NIEZNANE, z których wszystkie są zdefiniowane jako literały logiczne zgodnie ze standardem. Standard zapewnia również, że NULL i UNKNOWN "mogą być używane zamiennie, aby oznaczać dokładnie to samo".

Typ boolowski był przedmiotem krytyki, szczególnie ze względu na nakazane zachowanie literału NIEZNANEGO, który nigdy nie jest sobie równy ze względu na identyfikację z NULL.

Jak omówiono powyżej, w implementacji SQL w PostgreSQL , wartość Null jest używana do reprezentowania wszystkich NIEZNANYCH wyników, w tym UNKNOWN BOOLEAN. PostgreSQL nie implementuje literału UNKNOWN (chociaż implementuje operator IS UNKNOWN, który jest funkcją ortogonalną). Większość innych głównych dostawców nie obsługuje typu Boolean (zgodnie z definicją w T031) od 2012 roku. Część proceduralna PL Oracle /SQL obsługuje jednak zmienne BOOLEAN; można im również przypisać NULL, a wartość jest uważana za taką samą jak UNKNOWN.

Spór

Częste błędy

Niezrozumienie sposobu działania Null jest przyczyną dużej liczby błędów w kodzie SQL, zarówno w standardowych instrukcjach SQL ISO, jak i w konkretnych dialektach SQL obsługiwanych przez rzeczywiste systemy zarządzania bazami danych. Te błędy są zwykle wynikiem pomylenia wartości Null z 0 (zero) lub pustym ciągiem (wartość ciągu o długości zero, reprezentowana w SQL jako ''). 0Jednak wartość null jest zdefiniowana przez standard SQL jako różna zarówno od pustego ciągu znaków, jak i wartości liczbowej . Podczas gdy Null wskazuje na brak jakiejkolwiek wartości, pusty ciąg i zero numeryczne reprezentują rzeczywiste wartości.

Klasycznym błędem jest próba użycia operatora równości =w połączeniu ze słowem kluczowym w NULLcelu znalezienia wierszy z wartościami Null. Według standardu SQL jest to nieprawidłowa składnia i powinna prowadzić do komunikatu o błędzie lub wyjątku. Ale większość implementacji akceptuje składnię i ocenia takie wyrażenia do UNKNOWN. Konsekwencją jest to, że nie zostaną znalezione żadne wiersze – niezależnie od tego, czy wiersze z wartościami Null istnieją, czy nie. Proponowanym sposobem pobierania wierszy z wartościami Null jest użycie predykatu IS NULLzamiast = NULL.

SELECT *
FROM sometable
WHERE num = NULL;  -- Should be "WHERE num IS NULL"

W podobnym, ale bardziej subtelnym przykładzie WHEREklauzula lub instrukcja warunkowa może porównywać wartość kolumny ze stałą. Często błędnie zakłada się, że brakująca wartość byłaby „mniejsza niż” lub „nie równa” stałej, jeśli to pole zawiera wartość Null, ale w rzeczywistości takie wyrażenia zwracają Unknown. Przykład znajduje się poniżej:

SELECT *
FROM sometable
WHERE num <> 1;  -- Rows where num is NULL will not be returned,
                 -- contrary to many users' expectations.

Te nieporozumienia powstają, ponieważ prawo tożsamości jest ograniczone w logice SQL. Kiedy mamy do czynienia z porównaniami równości przy użyciu NULLliterału lub wartości UNKNOWNprawdziwości, SQL zawsze zwróci UNKNOWNwynik wyrażenia. Jest to częściowa relacja równoważności i sprawia, że ​​SQL jest przykładem logiki nierefleksyjnej .

Podobnie wartości null są często mylone z pustymi ciągami. Rozważmy LENGTHfunkcję, która zwraca liczbę znaków w ciągu. Po przekazaniu wartości Null do tej funkcji funkcja zwraca wartość Null. Może to prowadzić do nieoczekiwanych wyników, jeśli użytkownicy nie są dobrze zorientowani w logice trójwartościowej. Przykład znajduje się poniżej:

SELECT *
FROM sometable
WHERE LENGTH(string) < 20; -- Rows where string is NULL will not be returned.

Komplikuje to fakt, że w niektórych programach interfejsu baz danych (lub nawet implementacjach baz danych, takich jak Oracle), NULL jest zgłaszany jako pusty ciąg, a puste ciągi mogą być nieprawidłowo przechowywane jako NULL.

Krytyka

Implementacja Null ISO SQL jest przedmiotem krytyki, debaty i wzywa do zmian. W The Relational Model for Database Management: Version 2 Codd zasugerował, że implementacja SQL Null była błędna i powinna zostać zastąpiona dwoma różnymi znacznikami typu Null. Zaproponowane przez niego znaczniki miały oznaczać „Brakujące, ale możliwe do zastosowania” i „Brakujące, ale niemożliwe do zastosowania” , znane odpowiednio jako wartości A i I-wartości . Rekomendacja Codda, gdyby została zaakceptowana, wymagałaby implementacji czterowartościowej logiki w SQL. Inni sugerowali dodanie dodatkowych znaczników typu Null do zaleceń Codda, aby wskazać jeszcze więcej powodów, dla których wartość danych może być „Brakująca”, zwiększając złożoność systemu logicznego SQL. W różnych momentach pojawiały się również propozycje implementacji wielu zdefiniowanych przez użytkownika znaczników Null w SQL. Ze względu na złożoność systemów obsługi wartości Null i systemów logicznych wymaganych do obsługi wielu znaczników wartości Null, żadna z tych propozycji nie zyskała powszechnej akceptacji.

Chris Date i Hugh Darwen , autorzy The Third Manifesto , zasugerowali, że implementacja SQL Null jest z natury wadliwa i powinna zostać całkowicie wyeliminowana, wskazując na niespójności i błędy w implementacji obsługi SQL Null (szczególnie w funkcjach agregujących) jako dowód na to, że cała koncepcja Null jest błędna i powinna zostać usunięta z modelu relacyjnego. Inni, jak autor Fabian Pascal , wyrażają przekonanie, że „to, w jaki sposób obliczenia funkcji powinny traktować brakujące wartości, nie jest regulowane przez model relacyjny”.

Założenie zamkniętego świata

Innym punktem konfliktu dotyczącym wartości Null jest to, że łamią one model założenia o zamkniętym świecie relacyjnych baz danych, wprowadzając do niego założenie otwartego świata . Założenie zamkniętego świata, w odniesieniu do baz danych, mówi, że „Wszystko podane przez bazę danych, jawnie lub niejawnie, jest prawdziwe; wszystko inne jest fałszywe”. Ten widok zakłada, że ​​wiedza o świecie przechowywana w bazie danych jest kompletna. Nulls działają jednak przy założeniu otwartego świata, w którym niektóre elementy przechowywane w bazie danych są uważane za nieznane, co sprawia, że ​​przechowywana w bazie wiedza o świecie jest niekompletna.

Zobacz też

Bibliografia

Dalsza lektura

Zewnętrzne linki