Relációs adatbáziskezelés

NULL

NULL.jpg

Azért az SQL, illetve a relációs adatbáziskezelés még ma sem tökéletes. Lássunk ízelítőül egy problémát, a NULL jelek problémakörét.

Egy adatbázisból kétféle módon hiányozhat ismeret. Vagy egész sor hiányzik egy táblából, azaz egy (vagy több) egyedelőfordulás nem szerepel, holott annak szerepelnie kellene. Ez az eset kívül esik a relációs elvű kezelés határain, modellezési-tervezési vagy üzemeltetési hiba eredménye lehet. („Az egyetlen mód, hogy ne hiányozzon a névsorból: ő olvassa.”)

A másik eset, amikor a sor a „helyén van”, csak egyes adatelemei hiányoznak, nem kap értéket minden tulajdonsága, másképpen mondva vannak üres cellák a sorban. Ez az eset különféle problémákat vet föl, amelyeket valamilyen módon kezelni kell.

Az adatmodell fogalmának tisztázása során leszögeztük, hogy „megnevezzük a fontos tulajdonságokat (...) leírjuk (...) tartalmukat”. Ebből az következne, hogy minden tulajdonságnak minden esetben van értéke, holott ez nem biztos, hogy így van. Ha pontosabban végiggondoljuk a fenti fogalommeghatározást, akkor világossá válik, hogy nem erről van szó benne. A „leírjuk (...) tartalmukat” kitétel nem szükségképpen jelenti azt, hogy minden egyes esetben ismerjük az adott tulajdonság értékét, sőt még azt sem, hogy annak minden esetben lenne egyáltalán értéke.

Egy példával megvilágítva: egy háziorvosi nyilvántartásban elképzelhető olyan rovat, hogy a páciens (adott pillanatig, összesen) hányszor szült. Ez nyilvánvalóan egy nemnegatív egész számmal leírható ismeret. Értéke különböző esetekben lehet: a) pozitív szám, amikor tudjuk, hogy az adott hölgy hányszor is szült (pl. négyszer); b) nulla, amikor tudjuk, hogy az adott hölgy (még) nem szült egyszer sem (a szignifikáns nulla példája). Eddig problémamentes. Probléma azokkal a hölgyekkel van, akikről nem tudjuk, hogy hányszor szültek. Esetükben a megfelelő rovat üres marad (az inszignifikáns nulla esete), míg férfiak esetében szintén üres marad, de a két „üres” állapot nem egyenértékű. Férfiak esetében ugyanis a „szülések száma” nem értelmezhető („n.a.” - not applicable, és nem pedig „nincs adat”). E két utóbbi esetet azonban mindenképpen szükséges megkülönböztetni egymástól, a valósághű modellezés követelményén túl csak egyetlen példával érzékeltetve: ha születésszám-statisztikát kell készíteni, nyilván nem számolhatjuk bele nemcsak a férfiakat, de azon hölgyeket sem, akiknél az adat értéke - egyelőre - ismeretlen.

Erre a problémára született az a megoldási kísérlet, hogy az adatbáziskezelők egy különleges, NULL elemmel jelzik azt, ha az adott érték nem létezik. Ez mutatja azt, hogy az adott helyzetben az adat értéke ismeretlen, de nem különbözteti meg az „ismeretlen” esetét a „nem értelmezhető” esetétől, azaz két elvileg különböző esetet egybemos.

Ráadásul a hiányzó értékek problémája adattípusfüggő. Numerikus adatok esetében ugyanis a hiányzó érték és a „nem értelmezhető” nem különböztethető meg, ugyanis nincs üres numerikus adat az üres szövegessel ellentétben. (Bárki kipróbálhatja: egy táblázatkezelő cellájába beírandó tetszőleges képlet hivatkozzon egy üresen hagyott cellára. A képlet nulla értékkel fog számolni az üres cella helyén.) Szöveges típusú adat esetében ugyanis van „üres” adat, az ún. üres string, amelyet olyan szövegkonstansként lehet megadni, amely semmit nem tartalmaz (insert into <táblanév> set <mezőnév>="";), azaz valóban az „ürességet” képviseli. Numerikus esetben azonban a nulla (0) az mindig szignifikáns. Így szöveges típusú adatelem esetében meglenne az „üres” („pillanatnyilag nem ismerem az adatot”) jelentéstartalom is és a „nem értelmezhető” (NULL) jelentéstartalom is, viszont ugyanez numerikus adatelemek esetében így nem áll fenn, tehát a helyzetet súlyosbítjuk avval, hogy a jelenség függ az adatelemek típusától.

Ezen problémakör a kezdet kezdete óta fennáll, és máig nincs rá megnyugtató és egyértelműen világos megoldás. Ezt jelzi már az is, hogy Ullman és Widom azt írják kitűnő könyvükben, hogy „Ugyan a nullértékek nem képezik részét a hagyományos relációs modellnek, de azért nagyon hasznos és kiemelkedő szerepet játszanak az SQL lekérdezőnyelvben”.

Állításukkal ellentétben már az „alapító atya”, Codd meglepően terjedelmesen és részletesen foglalkozik a problémával, idézett könyvében a teljes 8. fejezet (Chapter 8. Missing Information) erről szól, míg a 9. fejezet az evvel kapcsolatos technikai kritikákkal foglalkozik (Chapter 9. Response to Technical Criticisms Regarding Missing Information). Ezen kívül a 13. számú követelményben (RS-13) foglalkozik a hiányzó ismeret kezelésének módjával: „Azt a körülményt, ha egy érték nem áll rendelkezésre, az egész adatbázisban egységesen és módszeresen kell jelölni, függetlenül a hiányzó érték adattípusától. Erre a célra jelek szolgálnak.” Azaz a hiányzó adat jelzése nem érték, hanem valamilyen más módon megvalósított jelzés.

A hiányzó, de az adott körülmények között értelmezhető eset jelölésére szolgálna az ún. A-jel (applicable), míg a nem értelmezhetősége okán való hiányt az I-jel mutatja (inapplicable). A máig általánosan meglévő és használt NULL nem szerencsés megoldás és nem szerencsés elnevezés, mert valójában nem érték (ez az SQL szintaktikán is meglátszik, mert a 17 éveseket úgy kell lekérdezni, hogy „...where Kor=17”, míg azokat, akiknek az életkora hiányzik, azokat nem úgy, hogy „...where Kor=NULL”, hanem így: „...where kor is NULL”). Továbbá fennáll az a probléma, hogy két különböző esetet kellene megkülönböztetni az egyféle NULL használatával, ami nem megy.

Általánosabban fogalmazva, adatbázisok esetén a kétértékű logika nem elegendő. Az általánosan alkalmazott háromértékű logika is kevés, négyértékű logikára van szükség. Ezt Codd már 1986-87-ben, lassan negyedszázada leszögezte. A négyértékű logika implementálása nem lenne nehezebb vagy időigényesebb, mint a háromértékűé. Codd rámutat arra is, hogy ennek precíz megoldása fölöslegessé tenné a NULL használatát az SQL-ben. A NULL kiküszöbölése pedig egyszerűbbé és egyértelműbbé tehetné a relációs adatbáziskezelés egyes területeit.

Date ugyancsak a NULL jel használata ellen érvel a relációs adatbáziskezelés kapcsán.

Lehetne azonban másképpen is érvelni, a valóság modellezésének oldaláról közelítve a problémához. Ebben az esetben viszont, a hasonlóság követelményéből kiindulva megkockáztathatjuk, hogy nem is lenne szükség a „nem értelmezhető” jelentéstartalomra, amikor a NULL jel maradna az „adat még ismeretlen” állapot jelzésére. Ha ugyanis a valóságot modellezem, akkor kiragadom a számomra fontos jelenségeket, továbbá azok tulajdonságait. Egy létező jelenség létező tulajdonsága pedig nehezen elképzelhető, hogy értelmezhetetlen legyen. Másképpen fogalmazva, ha fölmerül adott helyzetben az - eseti - értelmezhetetlenség problémája, az valamilyen modellezésbeli pontatlanságra vezethető vissza.

Ez azonban egy olyan terület, ahol az elméleti teljesség és hibátlanság csak jelentősen nagyobb bonyolultság árán lenne elérhető. Célszerű tehát kisebb engedményt tenni az elméleti teljesség kárára a könnyebb és hatékonyabb modellezés érdekében, nem tévesztve szem elől azt, hogy az adott esetben értelmezhetetlen tulajdonságok gyakorisága a modell jóságának mértékére is utalhat.

Az üres/hiányzó értékek eddig vázolt problémája gyakorlatias eszközökkel kezelhető minden olyan esetben, ahol az múlhatatlanul szükséges, megfelelő további tulajdonságok beiktatásával. Vannak azonban további problémák is a NULL használata körül, és ezeket máig sem sikerült megnyugtató módon tisztázni. Márpedig nagyon kellemetlen, hogy egy közel negyven éves eszközben, amelynek szilárd matematikai alapjai vannak, ilyen tisztázatlan, nem egyértelmű, nem megnyugtató módon rendezett megoldások (illetve megoldatlan problémák) legyenek.

A legalább háromféle lehetséges megoldás van. Az első lehetőség a valószínűségi adatbázisok használata (többértékű logika), amely a matematikusok számára vonzó lehet ugyan, de az emberiség nagyobbik hányada nehezen emésztené meg, különösen hétköznapi helyzetekben.

A másik megoldás a NULL jel mellett az EMPTY jel bevezetése volna. Az utóbbi jelezné, hogy az adat értelmezhető, de értéke még nem ismert, míg az előbbi jelezné, hogy az adott helyen az adott adat nem értelmezhető. Ez a megoldás mind az SQL szabvány, mind az adatbáziskezelők módosítását megkövetelné.

A harmadik megoldás nem érintené az SQL szabványt, csak a kezelők módosítását követelné meg: ha a numerikus adatok is karakteresként tárolódnának, akkor a fentebb írtak szerint lenne ténylegesen üres adat, és a NULL jel elegendő lenne a nem értelmezhető esetekre.

Igaz tehát, hogy a fentebb vázolt okfejtés alapján a hiányzó adatok problémaköre - elméletileg legalábbis - könnyen és gyorsan megoldható lenne. Mivel azonban ez a problémakör évtizedek óta jelen van, nem biztos, hogy összességében ez volna a leghatékonyabb megoldás. Már Codd fontos szempontnak tartja korai munkáiban is a kompatibilitás kérdését mint a felhasználók jogos és igen fontos érdekét. Így tehát marad a fennálló állapot - legalábbis még jó darabig - és az adott helyzet megkívánta módon orvosoljuk az elméleti probléma gyakorlati előfordulását technikai eszközökkel.

Date már 1975-ben példát mutatott arra, hogy a NULL használata esetén az SQL esetenként hibás eredményeket szolgáltat. Rubinson 2007-es cikke (NULL, háromértékű logika és kétértelműség az SQL-ben: Date kritikájának kritikája) vitába száll Date eredeti véleményével, mire válaszként megjelenik John Grant 2008-as cikke ugyanerről a kérdésről.

Date eredeti példája a következő: Legyen két tábla az adatbázisban: SZÁLLÍTÓ(sno, város) és ALKATRÉSZ(pno, város). Mindkét táblának egyetlen sora van, a SZÁLLÍTÓ esetében ez (s1,'London'), az ALKATRÉSZ esetében ez (p1,NULL), azaz a p1 azonosítójú alkatrész városa ismeretlen. Date kérdése: listázzuk azokat a sno-pno párokat, amelyek esetén a szállító és az alkatrész városa különbözik, vagy pedig az alkatrész városa nem Párizs. Az SQL ma megszokott formájában ez mint lekérdezés így nézhetne ki (az ékezetektől eltekintve):

SELECT sno,pno from SZÁLLÍTÓ,ALKATRÉSZ

WHERE SZÁLLÍTÓ.város<>ALKATRÉSZ.város OR

ALKATRÉSZ.város<>'Párizs';

Az SQL válasza egy üres tábla. Date viszont azt mondja, hogy az (s1,p1) páros az elvárt válasz, és úgy érvel, hogy ha p1 ismeretlen városa Párizs lenne, akkor a feltétel második fele nyilván teljesül. Ha viszont p1 városa nem Párizs, akkor teljesül a feltétel első fele, ezeket a vagy logikai operátor kapcsolja össze, tehát a teljes feltétel a p1 bármilyen városa esetében igaz, így a válaszban benne kellene legyen az (s1,p1). De nincs. Pedig jogosan érezzük úgy, hogy a világ bármely városára igaz az az állítás, hogy az vagy Párizs, vagy nem az.

Egy másik, hasonló problémát mutat be Codd egyik példája. Legyen egyetlen táblánk, amely alkalmazottak születési éveit (is) tartalmazza: ALKALMAZOTT(ano,...,születés_éve). Legyenek a következő évszámok a táblában: 1939, 1940, 1940, NULL.

SELECT * from ALKALMAZOTT

WHERE születés_éve<1940 OR

születés_éve=1940 OR

születés_éve>1940;

Ebben az esetben a válasznak mind a négy sort tartalmaznia kellene, hiszen hiába ismeretlen a negyedik dolgozó születési éve, akkor is biztosra vehető, hogy ha az nem is pont 1940, akkor azt vagy megelőzi, vagy pedig nagyobb annál. Codd azt javasolja, hogy a jövőbeni adatbáziskezelőket fel kell készíteni az efféle egyszerű tautológiák felismerésére.

Véleményem szerint nem az a probléma, ha egy lekérdezésre nem - a saját logikánk szerint - elvárható választ kapjuk. Az első példabeli jelenségre ugyanis az a válasz, hogy azért van így, mert az ANSI így alkotta meg az SQL szabványt - dacára Codd, Date, Maier és mások munkásságának. Azazhogy a példabeli jelenség az SQL-nek nem hibája, hanem tulajdonsága. Az igazi probléma az, ha valamitől olyasmit várunk el, ami nem lenne feladata, ha megalapozatlanul - esetleg az értelmezési tartományon túlra - extrapolálunk.

Mindkét példa esetében igaz az, hogy a természetes észjárás alapján, pontosabban az egyik lehetséges természetes észjárás alapján elvárt választ nem kapjuk meg. A másik lehetséges megközelítési módja az efféle problémáknak ugyanis az, hogy az ismeretlen érték - éppen ismeretlen mivolta okán - nem vehet részt érdemi értékelésben. Mindkét példabeli esetben ugyanis az elvárt válasz feltételezné, hogy az SQL kérés feldolgozása során a kérdés jelentésén alapuló értelmezést végezzen az SQL parancsértelmező. Ez pedig - szerintem - messze nem feladata. Már csak azért sem, mert az említett példák aránylag egyszerűek. Ha elvárnánk az SQL-től, hogy az ilyesféle eseteket a példabeli módon kezelje, akkor igen komoly tartalmi-logikai elemzést (intelligenciát) kellene beleépíteni, hogy minden lekérdezés esetén végezze el az ehhez hasonló elemzéseket - hogy milyen eredménnyel, azt előre nem lehet megjósolni. Tehát jobb, ha inkább következetesen nem teszi.


Lásd még (a teljesség igénye nélkül):

Ullman Jeffrey D. - Widom Jennifer: Adatbázisrendszerek. Alapvetés. Panem, Budapest, 2008.

Codd E. F.: The Relational Model for Database Management - version 2. Addison-Wesley Publishing Company, h.n., 1990.

Date, C. J.: Database in Depth: Relational Theory for Practitioners. O'Reilly, h.n., 2005.

Grant J.: Null Values in SQL. In: ACM SIGMOD Record, Association for Computing Machinery Special Interest Group on Management of Data, 2008., XXXVII. évf. 9. szám pp. 23-25.

Date C. J.: An Introduction to Database Systems. Addison-Wesley, h.n., 2004.

 

Vélemény

Nincs és nem is lehet.

impresszum

Alapfogalmak