Iako je SQL jedan od najstarijih programskih jezika koji je još uvek u upotrebi, skoro svaki database engine koji ga koristi poseduje sopstvenu implementaciju, koja se manje ili više razlikuje od standarda. Iako baziran na SQL92 standardu, SQLite po tom pitanju nije mnogo bolji, a osim toga neke potrebne komande/mogućnosti mu još nisu implementirane. Na primer, LEFT OUTER JOIN je podržan, ali ne i RIGHT i FULL OUTER JOIN (RIGHT JOIN je uvek moguće zameniti sa LEFT JOIN, uz promenu redosleda odgovarajućih tabela/upita, dok FULL JOIN može biti zamenjen unijom dva upita sa LEFT i RIGHT JOIN izrazima). Nešto ozbiljniji problem je to što View nije moguće koristiti za promenu baze sa DELETE, INSERT ili UPDATE. Ukoliko do sada niste koristili Queries u Microsoft Jet-u (Access), pomenućemo da View predstavlja virtuelnu tabelu koja se čuva u bazi u obliku imenovanog SELECT upita, pri čemu je nju moguće koristiti u okviru drugih SELECT upita umesto postojećih tabela.
Na Web adresi en.wikibooks.org/wiki/SQL_dialects_reference pronaći ćete kraću knjigu u elektronskom obliku u kojoj su objašnjene najvažnije razlike između SQL standarda i nekoliko popularnih implementacija: IBM DB2, Firebird 2.0, MySQL 5.0, Microsoft SQL Server 2500, Oracle 10g2, PostgreSQL 8.2 i SQLite. Knjiga nije previše ažurna, a ima u njoj i grešaka, ali je dobra za sticanje predstave o mogućnostima pojedinih RDBM sistema – vredi pogledati uporedne tabele sa ekvivalentnim numeričkim/string funkcijama koje poseduju pomenuti programi. Ukoliko se vaše iskustvo sa bazama podataka uglavnom bazira na Access-u, pre nego što počnete da koristite SQLite moraćete da provedete izvesno vreme u proučavanju nove sintakse (www.sqlite.org/lang.html ).
Sličnosti i razlike
| (kliknite za veću sliku) |
Komande kao što su SELECT, CREATE... su slične, ali postoje i određene razlike. Na primer, umesto službene reči TOP kojom se navodi broj slogova koje želimo prikazati, treba koristiti LIMIT, i to na kraju SELECT izraza, tj. umesto SELECT TOP broj ... treba pisati SELECT... LIMIT broj. Operatori u SQLite-u su uglavnom isti kao u Access-u, a najvažnija razlika je u operatoru za nadovezivanje stringova, pa umesto & treba koristiti dve vertikalne crte (||). Operator <> može biti naveden i kao !=, a kod LIKE operatora umesto džoker znakova ? i * treba koristiti _ i %. LIKE operator, kao i u Access-u, nije osetljiv na mala/velika slova (Z je isto što i z), a ako želite da uporedite dve string vrednosti uzimajući u obzir veličinu slova, koristite operator GLOB. Nažalost, ugrađeni LIKE operator, kao i funkcije upper i lower za konverziju slova, funkcionišu kako treba samo sa engleskom abecedom: 'Z' like 'z' vraća 1, ali 'Ž' like 'ž' vraća 0. Ukoliko želite ispravan rad i sa našim slovima, moraćete da potražite neku biblioteku koja to podržava ili da modifikujete SQLite izvorni kod, o čemu će biti govora na kraju teksta.
Ukoliko ste navikli na Microsoft Jet i njegovo bogatstvo funkcija, u SQLite-u ćete se često susretati sa neshvatljivim nedostatkom elementarnih stvari (www.sqlite.org/lang_expr.html ). Ovo je posledica želje autora programa da napravi bazu koja bi bila što manja – veliki broj SQL funkcija i komandi realno i nije potreban za svakodnevne primene, ali po Marfiju može da nam zatreba upravo neka funkcija koja nije implementirana. Naročit problem predstavlja nedostatak numeričkih i string funkcija, dok su datumske/vremenske funkcije relativno dobro podržane, ali uz znatno drugačiju sintaksu i dejstvo u odnosu na Microsoft Jet. Međutim, puno toga se može uraditi uz pomoć neuobičajenih tehnika primene i kombinacije više postojećih funkcija.
Najjednostavniji slučaj je kada pojedine funkcije imaju drugačiju sintaksu, ali isto dejstvo: Len (string) se zamenjuje sa length (string), LCase (string) sa lower(string) a UCase(string) sa upper (string). Substr funkcija ima isto dejstvo kao i Mid, dok su Left i Right samo njeni specijalni slučajevi: Mid (string, start [, length]) je substr (string, start[, length]), Left (string, length) je substr (string, 1, length) a Right (string, length) postaje substr (string, -length, length).
Neke Microsoft Jet funkcije mogu biti zamenjene konstrukcijom CASE-WHEN-THEN-ELSE-END, recimo umesto IIf (expr, truepart, falsepart) koristi se CASE WHEN expr THEN truepart ELSE falsepart END a umesto Switch (expr-1, value-1[, expr-2, value-2 ... [, expr-n, value-n]]) poslužiće CASE WHEN expr-1 THEN value-1 [WHEN expr-2 THEN value-2 ... [WHEN expr-n THEN value-n]] END.
Specijalne tehnike
Pojedine funkcije za konverziju tipova podataka mogu donekle biti zamenjene standardnim Cast izrazom: Fix (number) zamenite sa CAST (number AS integer) a Str (expression) sa CAST (expression AS text). Direktna zamena za Chr funkciju ne postoji, ali u nuždi može biti upotrebljen ne baš tako očigledan Cast izraz: primera radi, umesto Chr (charcode) stavljate CAST (x'charcode' AS text). Da navedemo još jedan primer: CAST (x'2900' AS text) je isto što i Chr (&H29), pri čemu je za charcode potrebno navesti dvobajtnu vrednost kao heksadecimalni string, i to prvo bajt niže, a zatim više vrednosti.
Zeroblob funkcija je SQLite-u dodata u verziji 3.4.0 i služi za rezervisanje prostora binarnim podacima, ali može biti iskorišćena u neke svrhe za koje i nije namenjena. Na primer: String (number, 0) zamenite sa zeroblob (number). Niz nula bajtova vam možda neće biti potreban unutar SQL upita, ali je nedostak InStr funkcije u SQLite-u veoma neprijatan. Srećom, zeroblob može biti upotrebljen kod njene zamene: InStr (start, string1, string2) sa:
CASE WHEN replace (substr
(string1, start), string2,
zeroblob(1)) = substr(string1, start) THEN 0
WHEN length (string2) = 0 THEN start ELSE length (substr (string1, 1, start – 1) ||
replace(substr (string1, start), string2, zeroblob(1))) + 1
END
Četvrti argument InStr funkcije koji ovde nije naveden (0 označava default vrednost) određuje da li će komparacija uzimati u obzir veličinu slova, tako da je u navedenom primeru 'Z' različito od 'z'. Ukoliko želimo pretragu stringa sa komparacijom bez obzira na veličinu slova, u Microsoft Jet-u bi kao četvrti argument bilo dovoljno navesti 1, dok u SQLite izrazu moramo koristiti upper ili lower funkcije na odgovarajućim mestima.
Datumske/vremenske funkcije su takođe važne u radu, a zamene su često prilično složene. Recimo, funkcija koja vraća broj proteklih dana/nedelja/meseci/godina od zadatog do tekućeg datuma: DateDiff ('d', date1, Now) može se zameniti sa CAST (julianday(date('now', 'localtime')) – julianday (date(date1)) AS integer) + 1, DateDiff ('ww', date1, Now, firstdayofweek) se zamenjuje sa CAST (julianday (date ('now', 'localtime', '-6 days', 'weekday ' || (firstdayofweek – 1), CASE WHEN firstdayofweek = 1 THEN '0' ELSE '8' END || firstdayofweek || ' days')) – julianday(date(date1)) As integer) / 7 dok umesto DateDiff ('m', date1, Now) možete koristiti CAST (strftime('%Y', 'now', 'localtime') * 12 + strftime ('%m', 'now', 'localtime') – strftime ('%Y', date1) * 12 – strftime ('%m', date1) AS integer). Najzad, DateDiff ('yyyy', date1, Now) zamenite sa CAST (strftime('%Y', 'now', 'localtime') – strftime ('%Y', date1) AS integer).
Za (naj)upornije
Neke Microsoft Jet funkcije nije moguće zameniti SQLite funkcijama. I za to postoji nekoliko rešenja, ali samo ako sami razvijamo aplikaciju za rad sa bazom podataka. Ukoliko za programski jezik koji koristimo postoji neka već napravljena biblioteka koja sadrži SQLite database engine sa implementiranim funkcijama koje su nam potrebne, do rešenja se dolazi lako. Na primer, na adresi www.thecommon.net/2.html možete pronaći dhSQLite biblioteku koja se sastoji od svega dva DLL fajla ukupne veličine 350 KB i zamenjuje skoro kompletan Microsoft ADO/Jet sistem, sa implementiranim skoro svim VB funkcijama (IIf, InStr, DateDiff, DatePart...) i mogućnošću definisanja sopstvenih. Jedan od ta dva DLL fajla zahteva postojanje VB 6.0 run-time modula od oko 1,3 MB, ali se on dobija uz svaki Windows još od verzije 2000. Time ste rešili i problem naših slova.
Najkomplikovanije rešenje za implementaciju novih funkcija bazira se na modifikaciji SQLite izvornog koda i rekompajliranju /src/func.c fajla u kome se nalaze definicije internih funkcija. Počev od verzije 3.3.6 SQLite-a, postoji i mogućnost kreiranja dodatne biblioteke sa potrebnim funkcijama koje bismo koristili nakon poziva sqlite3_load_extension() API funkcije, što ne zahteva rekompajliranje samog SQLite database engine-a, ali zahteva upotrebu pomenutog poziva prilikom svakog pokretanja aplikacije.
Nakon čitanja svega ovoga i pregleda siromašnog spiska podržanih komandi/funkcija, mnogi će dići ruke od ove baze podataka, ali ako ste uporni, vaš trud će biti višestruko nagrađen prednostima koje SQLite nudi u odnosu na ostala preglomazna i često veoma skupa rešenja.
|