U prethodnoj lekciji smo funkcije podelili na skalarne i agregatne. Ipak, postoji još jedna, viša, podela od te: na korisnički definisane i ugrađene funkcije. Ugrađene funkcije su sve one funkcije koje podrazumeva standardna forma MySQL servera, dok su korisnički definisane one koje su izgrađene naknadno, od strane korisnika.
Kada su u pitanju korisnički definisane funkcije, na MySQL serveru one mogu biti realizovane na dva načina: kroz SQL skriptu (DDL) ili kroz izvorni programski jezik MySQL servera (c).
Kreiranje korisnički definisanih funkcija (UDF) kroz SQL je jednostavniji metod. Zapravo, sintaksa je veoma slična sintaksi za kreiranje uskladištenih procedura.
create function mojaFunkcija() returns varchar(20) return 'pozdrav';
Pogledajmo delove ove funkcije, jednu po jednu:
create function mojaFunkcija()
Ova linija je identična kao da smo kreirali i uskladištenu proceduru.
returns varchar(20)
Za razliku od procedure, funkcija može (i mora) vratiti samo jednu vrednost. Tip ove vrednosti mora biti definisan prilikom definisanja same funkcije. U ovom slučaju, to je varchar(20).
return 'pozdrav';
Funkcija ima samo jednu liniju koda. Ova linija vraća rezultat funkcije, a samim tim i prekida njeno izvršavanje. Kada bi posedovala više od jedne linije, morali bismo pribeći tehnici koju smo upotrebili i sa procedurama. Privremena zamena delimitera.
delimiter //
create function mojaFunkcija()
returns varchar(20)
begin
return 'pozdrav';
end//
delimiter ;
Za razliku od procedure, funkciju je moguće umetnuti u sam upit, što nam daje na raspolaganje velike mogućnosti za intervenciju na podacima u trenutku kreiranja izlaza.
Na primer:
Funkciju pozivamo njenim umetanjem u upit:
select mojaFunkcija()
U prethodnoj lekciji smo smo, u samom upitu iz koje je države kupac i na osnovu toga ispisivali određeni tekst (lokaciju). Ovaj primer zahtevao je veliki upit. Ovo nije problem ukoliko taj upit upotrebimo jednom i nikada više, ali ne i ako se on ponavlja više puta.
Evo kako bismo taj primer realizovali kroz UDF:
drop function mojafunkcija;
delimiter //
create function mojaFunkcija(drzava varchar(50))
returns varchar(50)
begin
set @izlaz = 'nema naziv';
if drzava = 'CA' then set @izlaz='zapadna obala'; end if;
if drzava = 'NY' then set @izlaz='istocna obala'; end if;
return @izlaz;
end//
delimiter ;
Ako izvršimo sledeći upit, rezultat će biti isti kao u prethodnoj lekciji, pri čemu je upit čitljiviji. Pored toga, izmene na funkcionalnosti vršimo samo na jednom mestu: u samoj funkciji.
select mojafunkcija(state), customername from customers;
Iz ovih primera, zaključuje se da su uskladištene funkcije i procedure veoma slične po prirodi. Osnovne njihove razlike su u broju izlaznih parametara (funkcija može da vrati jedan, a procedura više) i načinu pozivanja (funkcija se može pozvati iz upita).
Osim uskladištenih, postoji još jedna vrsta korisnički definisanih funkcija, pomenuta na početku: to su funkcije pisane izvornim jezikom (c). Ove funkcije su mnogo brže od uskladištenih, ali je njihovo kreiranje delako komplikovanije, tako da se, u njihovu kreaciju ne ulazi bez velike potrebe. Pošto je osnova za kreiranje ovakvih funkcija odlično poznavanje jezika C, opisivanje tog procesa izašlo bi iz konteksta ovog kursa.
If
U prethodnom primeru, koristili smo sledeću liniju:
if drzava = 'CA' then set @izlaz='zapadna obala'; end if;
Ovo je sintaksa jedne od osnovnih naredbi za kontrolu toka i simbola programiranja uopšte naredbe If. If kontrolni operator, jednostavno, nagoveštava sistemu da će se nešto u narednom toku programa izvršiti uslovno. U primeru, rekli smo: ako je država CA, onda će promenljiva izlaz, biti zapadna obala.
Evo kako bismo proverili vrednost neke promenljive i na osnovu toga izvršili neku operaciju:
if @mojaPromenljiva>0 then
set @mojaPromenljiva=@mojaPromenljiva-1;
endif;
Razlikujemo nekoliko sekvenci u ovom uslovu: prva je sam uslov (if @mojaPromenljiva>0 then). Uslov počinje ključnom rečju if, zatim ide uslovni izraz (u ovom slučaju, mojaPromenljiva mora biti veće od 0) i zatim ključna reč then.
Nakon ključne reči then, počinje blok koda. U ovom slučaju, to je jedna linija, koja umanjuje vrednost promenljive mojapromenljiva za jedan, ali može biti i više linija.
Blok se završava naredbom endif;
If uslovni blok može imati i alternativne blokove, uz pomoć else klauzule. U tom slučaju, umesto da blok završimo endif naredbom, mi aktiviramo alternativni uslov:
if @mojaPromenljiva>0 then
set @mojaPromenljiva=@mojaPromenljiva-1;
else if @mojaPromenljiva<0 then
set @mojaPromenljiva=@mojaPromenljiva+1;
else
set @mojaPromenljiva=0;
endif;
Na kraju, u svakom slučaju, moramo zatvoriti blok endif; naredbom.
Nemojte zaboraviti da je jedan od načina za kontrolu toka i switch case struktura, pominjana u prethodnoj lekciji.
While
Još jedan bitan način za kontrolu toka programa su petlje. Najčešće korišćene petlje u programiranju su while i for (i njihovi derivati).
Petlja while započinje ključnom rečju while. Nakon toga sledi uslovni izraz i ključna reč do.
Sve što se nalazi iza ključne reči do, biće izvršavano prilikom svake iteracije petlje. Kada uslov petlje ne bude više ispunjen, ona se završava iskazom end while;
set @x=10;
while @x > 0 do
set @x=@x-1;
select @x;
end while;
While petlja je karakteristična po tome što se obično koristi kada ne znamo tačno koliko će nam puta biti potrebno izvršavanje njenog bloka. S obzirom na to da se uslov za zaustavljanje ove petlje obično reguliše u samoj petlji, veoma je bitno da ne dovedemo petlju u situaciju da se nikada ne završi (mrtva petlja). U primeru, ovo bi se desilo kada ne bi vrednost x smanjivali za jedan prilikom svake iteracije.
Loop
Loop se ne razlikuje mnogo od while petlje. Na početku, potrebno je inicijalizovati petlju dodelom naziva (petlja: loop). Nakon toga, blok koda počinje i traje sve do naredbe end loop (end loop petlja;). Petlja se izvršava se sve dok ne bude prekinuta naredbom leave (leave petlja;).
set @x=10;
petlja: loop
set @x=@x-1;
select @x;
if @x<=0 then
leave petlja;
end if;
end loop petlja;
Repeat
Repeat je petlja koja se izvršava sve dok se ne ispuni određeni uslov. Karakteristično za nju je to što, čak i da se uslov nikada ne ispuni, telo petlje će biti izvršeno bar jednom. Iz drugih programskih jezika, ovu petlju poznajemo kao do while petlju.
Repeat počinje ključnom rečju repeat, nakon čega sledi telo petlje. Petlja se završava naredbom until, kojoj sleduje uslov i naredba (until @x = 0 end repeat):
repeat
set @x = @x - 1;
select @x;
until @x = 0 end repeat;
Iterate i leave
Ove dve naredbe omogućavaju prelazak na sledeću iteraciju (sledeći krug petlje) ili bezuslovno napuštanje petlje, u loop petlji. Kao parametre prihvataju naziv petlje:
iterate petlja; - Prelazi na sledeću iteraciju
leave petlja; - Napušta petlju
For each
Ova petlja izvršava iteraciju kroz tabelarnu strukturu, omogućavajući određenu akciju na svakom podatku ponaosob. Važi samo za okidače pa je nećemo preterano obrađivati.
for each row set @x = @x + 1;
Najvažnije iz lekcije:
Problem:
Potrebno je napraviti funkciju checkNum, koja će prihvatati jednu vrednost, tipa int i vraćati vrednost tipa varchar. Kada broj uđe u funkciju, proverava se njegova vrednost. Ukoliko je nula, funkcija vraća tekst the number is zero, ukoliko je vrednost manja od pet a veća od 0, funkcija vraća tekst lower than 5, ukoliko je vrednost veća od 5, funkcija vraća higher than 5 i ako je pet, povratna vrednost je the number equals 5
Rešenje:
create function checkNum(num int)
returns varchar(50)
begin
set @izlaz = 'unknown';
if num = 0 then set @izlaz = 'The number is zero'; end if;
if num < 5 and num != 0 then set @izlaz='Lower than 5'; end if;
if num > 5 then set @izlaz='Higher than 5'; end if;
if num = 5 then set @izlaz='The number equals 5'; end if;
return @izlaz;
end//
Napomena:
Ukoliko je binarni log uključen, može doći do konflikta, i funkcija neće moći da bude kreirana, jer sistem neće moći da identifikuje da li funkcija utiče na podatke koji se loguju, tada treba dodati opciju deterministic u deklaraciji funkcije ili uključiti opciju log_bin_trust_function_creators:
SET GLOBAL log_bin_trust_function_creators = 1;
ili
create function checkNum(num int)
returns varchar(50) deterministic
begin
...
Problem:
Potrebno je napraviti funkciju setStatus, koja će menjati statuse korisnika u tabeli users. Ova funkcija mora da prihvata dva parametra, username i statusname. Na osnovu statusname parametra, preuzima se ID iz tabele statuses, a zatim se taj ID postavlja za traženo ime korisnika u tabeli users.
Rešenje:
create function setStatus(username varchar(50),statusname varchar(50))
returns int
begin
set @statusId = 0;
select id from statuses where name = statusname into @statusId;
if @statusId != 0 then
update users set status = @statusId where name = username;
end if;
return @statusId;
end//