@Trtko: ma OK je da se koriste funkcije u kverijima, ali kad to ima smisla. Ali, ako funkcija u sebi sadrzi otvranaje rekordseta pa petlju kroz rekordset, to uglavnom moze da se izbegne. Ako ne moze - ne moze i to je OK. Medjutim, i kada ne moze da se izbegne funkcija sa rekordsetima, moze se uraditi na brzi i sporiji nacin.
Recimo, trazi se kveri sa kumulativima,
SELECT A.BrRacuna
, A.Iznos
, (SELECT SUM(B.Iznos) FROM Racuni AS B WHERE B.BrRacuna <= A.BrRacuna) AS Kumulativ
FROM Racuni AS A
Sad, neko ne ume da napise ovaj prilicno komplikovan kveri i odluci da napise funkciju koja za svaki racun sabira iznose svih prethodnih racuna plus tekuci. Funkcija bi izgledala otprilike ovako:
Code:
function Kumulativ(intBrRacuna AS integer) AS long
DIM db AS DAO.database
DIM rs AS DAO.recordset
DIM strSQL AS String
DIM lngKumulativ AS Long Integer
SET db = currentdb
strSQL = "SELECT SUM(Iznos) AS Kumul FROM Racuni WHERE BrRacuna <=" & cstr(intBrRacuna)
SET rs = db.openrecordset(strSQL)
lngKumulativ = 0
if rs.count <> 0 THEN
rs.movefirst
lngKumulativ = rs("Kumul")
end if
Kumulativ = lngKumulativ
rs.close
set db = nothing
end function
Funkcija izracunava isto sto i subquery. I vrlo je verovatno da JET engine koristi slicnu funkciju da bi izracunao rezultat subkverija.
Zasto ne bi onda nasa funkcija radila isto brzo kao i JET engine? Zato sto mi pravimo greske koje ne vidimo jer ni ne znamo da su greske.
Za 1000 rekorda, sto nije mnogo, funkcija bi se izvrsila 1000 puta. Ako zaboravimo da odradimo rs.close, imacemo 1000 instanci baze otvorene sa SET db = currentdb i 1000 rekordsetova otvorenih. Znas i sam sta se mose desiti kad se otvori a ne zatvori rekordset....
No, recimo da smo mi majstori i takve greske ne pravimo. Funkcija ce ipak biti sporija jedno 100 puta od kverija. asto? Primeti da sam bazu otvorio sa SET db = currentdb. To je spora operacija. Ima drugi, brzi nacin da se otvori baza kroz kod. Treba mi malo da pronadjem. Ako se neko seti neka mnapise odgovor, ako ne, ja cu ga napisati nadam se do kraja dana.