Izbjegavate li NULL?

baze podataka

Danas je na Pollitici pokrenuta tema o manipulaciji popisima birača. Na stranici Pretraživanje popisa birača možete provjeriti koliko na pojedinoj adresi ima birača. Sumnjive su adrese koje po pravilu imaju kućni broj 0 ili 900 i veći. Svi oni koji imaju iskustva s bilo kakvim komunalnim sustavima već pogađaju zbog čega su se pojavili ti nerealni brojevi. U pravilu se radi o adresama bez kućnog broja pa se u tom slučaju upisivala nula (broj 0) ili neki veliki broj (u ovom slučaju 900).


Sve to ne bi bilo dovoljan razloga za ovaj post da u navedenoj temi komentator petar8 nije ustvrdio da je logičan pristup po kojem se upisuje broj 0 tamo gdje ne postoji kućni broj. Na komentar da se u tom slučaju koristi NULL petar8 odgovara ali je pravilo da se null izbjegava - jer inače svako pretraživanje traži uzimanje u obzir da navedeno polje nema vrijednosti....


Ups...NULL se izbjegava zato da programer u pojedinim slučajevima ne bi trebao pisati dodatni uvjet u upit? To nije pravilo, to je glupost i lijenost i kosi se s još uvijek važećim pravilima za RDBMS-ove. Ima NULL svojih nedostataka, ima prijedloga koji bi te nedostatke mogli ukloniti, ali kako oni još nisu postali standard moramo se ravnati po starom standardu. Edgar F. Codd (18.4. mu je 6. godišnjica smrti) je tu bio poprilično jasan. NULL rješava potrebu da se u bazi prikažu informacije koje nedostaju ili nisu poznate. U spomenutom slučaju kućni broj nije poznat pa je jedino logično rješenje da se on označi kao NULL (nepoznat, bez vrijednosti).


Zašto programeri izbjegavaju NULL? Uglavnom zato jer u upitima zaboravljaju obraditi to nedostajanje vrijednosti, dobivaju neočekivane rezultate pa idu linijom manjeg otpora i koriste nulu ili prazan string. Dodatan problem predstavljaju i različite implementacije u pojedinim bazama. Npr. ako imate ORDER BY po polju koje može imati i NULL vrijednosti (npr. tablica natjecatelja koja ima polje pozicija koje neće imati vrijednost ako natjecatelj nije završio utrku ) Microsoft SQL Server će vam te natjecatelje s NULL pozicijom postaviti ispred natjecatelja s pozicijama, dok će Oracle i PostgreSQL te natjecatelje staviti iza natjecatelja koji imaju konkretnu vrijednost u polju pozicija.


NULL se koristi, i polje u tablici se označava da može imati NULL vrijednost, u slučaju kad postoji potreba da se slog spremi bez da je poznata vrijednost u tom ili takvim poljima. U navedenom slučaju s natjecateljima mi moramo biti svjesni da postoje oni koji nisu osvojili poziciju u utrci i oni imaju drugi status nego natjecatelji koji su utrku završili. Aplikacija koja bi obrađivala rezultate mora biti svjesna toga, a ne da zanemaruje problem koristeći nulu ili neki veliki broj. Izbjegavanje NULL-a može se u nekim slučajevima vratiti kao bumerang jer će programer na kraju pisati više koda nego da ga je koristio.


Primjer koji sam ja navodio, kad sam nedavno dokazivao da postoje slučajevi kad se NULL treba koristiti, je slučaj tablice u kojoj se sprema datum nečije smrti (npr. baza za udrugu za posmrtnu pripomoć). U toj tablici su navedeni i živi ljudi koji još nemaju datum smrti. Što će oni, kojima je logično da se NULL izbjegava, upisati u to polje? Neki nerealni datum? Bez obzira koliko taj datum bio daleko, nekima se ne bi dopalo da predviđate datum njihove smrti. Zanima vas popis živih članova? Ako ste usvojili petar8 logiku onda morate znati koji vam je granični datum pa su živi oni koji imaju taj granični datum. Ako se držite standarda onda su vam živi svi oni koji nemaju datum smrti. Što je logičnije?


Neki ne vole NULL-ove zato jer skoro sve funkcije za agregaciju ignoriraju NULL-ove. Zamislimo da je petar8 radio aplikaciju koja bilježi temperaturu u gradu i na temelju prikupljenih podataka vraća prosječnu temperaturu. Postoje dani kad temperatura iz nekog razloga nije očitana. Slog s tim datumom će imati NULL u polju temperatura. petar8 i njegova logika će se u tom slučaju imati problem jer ne mogu koristiti nulu (budući da regularna temperatura može imati tu vrijednost) pa će najvjerojatnije uzeti neku nerealnu vrijednost. -100 ili 100?! Kod ispisa prosječnih temperatura petar8 će dobiti čudne vrijednosti, pa će se sjetiti da mora dodati uvjet kako bi isključio dane kada nije bilo očitavanja. Oni koji su koristili NULL tih problema nemaju jer funkcija AVG isključuje takve podatke.


Budite oprezni u logičnom izbjegavanju NULL-ova. Možda jednog dana zaslužite svojih pet minuta slave na The Daily WTF portalu. ;-)



Komentari

17. travnja 2009. 11:05

Jedan od razllga ovakvih problema je što se (zbog štednje, ali i neznanja) pisanjem SQL upita i procedura bave oni developeri koji pišu i osnovni kod, a najčešće im je znanje SQL-a vrlo bazično i nekompletno. Idealno bi bilo -- barem kad je riječ o većim i kritičnijim aplikacijama (kao što je popis birača) -- imati posebnog SQL developera koji će znati što kada i zašto upotrijebiti. Programer poslovne logike tada ne mora uopće brinuti o tome što mu baza šalje, jer dobiva već pročišćene i jasno definirane podatke.

17. travnja 2009. 16:19

berislave, meni se vise cini da je problem u tome da tvrtke koje dobivaju takve poslove za drzavu zaposljavaju nekompetentne ljude kojima daju da rade na takvim (kriticnijim) projektima. i tako dolazimo do slucajeva iz komentara na pollitici kad se jos i neznanje opravdava i postavlja kao 'pravilo struke'.

18. travnja 2009. 13:58

Za primjer, Djangova ORM dokumentacija kaže "nemojte koristiti NULL u CharField poljima, radije koristite '' (prazan string)". Kriviti li nekoga, i koga, u ovom slučaju? :)

19. travnja 2009. 19:36

Gle, gle, ja u svojim primjerima nigdje nisam imao primjer sa stringom. ;-)

Django je namijenjen web aplikacijama, obično se obrađuju neke forme koje šalju podatke. U skoro svim ostalim slučajevima, osim stringa, možeš biti siguran da kad korisnik ne upiše vrijednost da možeš staviti NULL (ako je polje tako definirano). Što sa stringom? Iz forme ti stigne prazan string, da li je to zbog toga što je to nepoznata vrijednost ili je korisnik namjerno unio prazan string? Ne možeš biti siguran. I zbog toga su autori Djanga odlučili da po defaultu spremaju prazan string (to se u modelu može promijeniti).

2. lipnja 2009. 12:22

E, vidite, trebalo bi poznavati i problematiku popisa stanovništva prije nego se krene u raspravu. I možda obratiti malo pažnje pa uočiti da postoje slučajevi kada praksa ZAHTIJEVA postojanje bilo kakvog podatka - je li to zbog optičkog čitača ili zastarjelog sustava obrade potpuno je nevažno. Popisivači prolaze određeni rutinski tečaj prije nego što krenu u popisivanje - i dobiju jasnu instrukciju koja polja moraju biti popunjena (jer oni popunjavaju formular na papiru).

A što se tiče uporabe NULL vrijednosti, nitko ne kaže da je zabranjeno korištenje NULL-a, ali je znatno je lakše i programeru i projektantu baze kada se izbjegavaju. Uostalom, pogledajte broj bug-ova koji se javljaju tijekom programiranja, a neću ni spominjati kako je zgodno eksportirati podatke u neki drugi program (npr. Excel), odnosno bazu...

9. lipnja 2009. 10:15

Postoji cijeli niz bugova koji su nastali zbog toga jer je programerima nešto bilo lakše napraviti. Kad se radi o podacima onda treba voditi brigu o njihovom integritetu, a ne o tome što je programeru lakše. Velika je razlika između 0 (nula) vrijednosti i nepoznate vrijednosti. Kad NULL definirate kao nepoznatu vrijednost onda sve izgleda logički i sjeda na svoje mjesto. Kao i ono da NULL nije jednako NULL tj. dvije nepoznate vrijednosti nisu jednake.

Evo priloga raspravi .