Adatbázis-kezelés (PL/SQL) Kollekciótípusok Adatbázis-kezelés (PL/SQL)
Jelölések Az SQL, PL/SQL utasítások, nevek stb. (terminálisok) nagybetűvel szerepelnek, pl.: SELECT. A nemterminálisok kisbetűvel, pl.: eredmeny. Az alternatívákat függőleges vonal választja el egymástól ( | ). Az opcionális elemek szögletes zárójelben állnak ( [ ] ), pl.: [NOT NULL]. A kötelezően megadandó alternatívákat kapcsos zárójelek fogják közre ( { } ), pl.: {kifejezes | feltetel}. Az iteráció jelölésére három pont szolgál (...), pl.: utasitas [utasitas]...
A példákhoz használt adatbázis automata (azon, penz, reszl_azon, varos) ugyfel (azon, nev, szuletes, keret) szamla (azon, ugyf_azon, reszl_azon, osszeg, lejarat) reszleg (azon, varos, tartalek) tranzakcio (azon, aut_azon, szaml_azon, ugyf_azon, datum, osszeg) Itt az automata tábla reszl_azon attribútuma azt adja meg, hogy melyik bank részleghez tartozik az adott automata, a penz pedig az automatán rendelkezésre álló pénzösszeget tárolja. A tranzakcio tábla osszeg attribútumának egy-egy értéke, ha negatív előjelű, pénzlevételt, ha pozitív, számlafeltöltést jelöl. A példa adatbázisban a Zseton Bank részlegeiről van szó.
Alapok I. A kollekció azonos típusú adatelemek rendezett együttese. A PL/SQL-ben három kollekciótípus létezik: index alapú tábla, beágyazott tábla és dinamikus tömb. Mindhárom deklarálható PL/SQL blokk, alprogram és csomag deklarációs részében. A beágyazott tábla és dinamikus tömb típusai létrehozhatók adatbázis-objektumként is a CREATE utasítással. Az index alapú tábla csak PL/SQL utasításokban használható, a másik kettő ezzel szemben adatbázistábla attribútumának típusa is lehet, sőt majdnem kizárólag ilyen szerepben használják őket. A beágyazott tábla és dinamikus tömb indexeinek alsó határa: 1, az index alapú tábla indexei negatív egészek is lehetnek. A dinamikus tömb változó számú elemet tartalmazhat. Ezek maximális számát a deklaráció során meg kell adni. Az elemek mindig folytonosan, a kisebb indexű helyeken helyezkednek el. Az egyszer bevitt elemek nem törölhetők, csak cserélhetők.
Alapok II. A beágyazott táblánál az elemek szétszórtan helyezkednek el, az elemek közt tehát lehetnek lyukak. Bármelyik elem törölhető, az új elemeket tetszőleges indexű helyre betölthetjük. Az explicit módon nem inicializált beágyazott tábla és dinamikus tömb automatikusan NULL kezdőértéket kap. A kollekciók átadhatók paraméterként, így segítségükkel az adatbázis tábláinak oszlopai az alkalmazások és az adatbázis között mozgathatóak. Kollekciók elemei is lehetnek kollekció típusúak. Az index alapú tábla indexe BINARY_INTEGER típusú, a maximális tartomány tehát: -231… 231. Beágyazott tábla és dinamikus tömb esetén az indexek lehetséges felső határa: 231.
Kollekciók létrehozása Index alapú tábla: TYPE név IS TABLE OF elemtípus [NOT NULL] INDEX BY BINARY_INTEGER; Beágyazott tábla: TYPE név IS TABLE OF elemtípus [NOT NULL]; Dinamikus tömb: TYPE név IS {VARRAY | VARRYING ARRAY} (max_méret) OF elemtípus [NOT NULL] Az elemtípus nem lehet REF CURSOR. Beágyazott tábla és dinamikus tömb esetén más típusok sem használhatók. Lásd dokumentáció.
Kollekciók kezelése I. Ha beágyazott tábla és dinamikus tömb esetében nem létező elemre hivatkozunk, SUBSCRIPT_BEYOND_COUNT kivétel, ha az index a LIMIT-nél (lásd később) nagyobb vagy nem pozitív szám, SUBSCRIPT_OUTSIDE_LIMIT kivétel váltódik ki. A beágyazott tábla és a dinamikus tömb tulajdonképpen speciális objektumtípusok. Az explicit inicializáláshoz az adott típus konstruktorát kell meghívni. A konstruktor egy rendszer által létrehozott függvény, melynek neve megegyezik a típus nevével, paramétereinek száma tetszőleges (dinamikus tömb esetén a legfeljebb a megadott felső határ), a paraméterek típusa meg kell, hogy egyezzen a kollekció elemeinek típusával. Ha a konstruktort paraméterek nélkül hívjuk meg, üres kollekció jön létre, amelynek egyetlen eleme sincs. Ezért, ha egy elemének explicit módon szeretnénk értéket adni SUBSCRIPT_BEYOND_COUNT kivétel váltódik ki. Ehhez lásd az 1. példát a Kollekciok_pelda.html fájlban.
Kollekciók kezelése II. Ez a szokatlan viselkedés annak köszönhető, hogy ezt a két kollekciótípust általában táblák attribútumai kapják értékként, ezért, ha „rendes tömböt” szeretnénk használni, amilyenhez más programozási nyelvben szoktunk, indexelt táblát kell használnunk. Egyébként pedig beágyazott tábla és dinamikus tömb típusú változó deklarálásakor érdemes inicializálni is a változót. Indexelt tábla esetén, ha olyan elemre hivatkozunk, amelyet még nem inicializáltunk NO_DATA_FOUND kivétel váltódik ki. Ehhez lásd a 2. példát a Kollekciok_pelda.html fájlban. Ha az index NULL vagy nem konvertálható egésszé, akkor VALUE_ERROR kivétel következik be. Beágyazott táblák és dinamikus tömbök esetében, ha nem inicializált kollekcióra hivatkozunk, COLLECTION_IS_NULL kivétel váltódik ki.
TABLE utasítás DML-utasításokban használható a TABLE (kollekciokifejezes) utasításrész. A kollekciokifejezes itt lehet alkérdés, oszlopnév, beépített függvényhívás. Minden esetben beágyazott tábla vagy dinamikus tömb típusú kollekciót kell szolgáltatnia. A TABLE segítségével az adott kollekció elemeihez mint egy tábla soraihoz férhetünk hozzá. Skalár típusú elemek kollekciójánál COLUMN_VALUE lesz az egyetlen oszlop értéke. Ez beágyazott táblák esetén fontos, ezért nem nézünk rá példát.
CAST függvény DML-utasításokban a CAST függvény segítségével adatbázis vagy kollekció típusú értékeket tudunk másik adatbázis vagy kollekciótípusra konvertálni. Alakja: CAST({kifejezes | (alkerdes) | MULTISET(alkerdes)} AS tipusnev) A tipusnev adja meg azt a típust, amibe a konverzió történik. Ez lehet adatbázis típus vagy adatbázisban tárolt kollekciótípus neve. A kifejezés vagy alkerdes határozza meg a konvertálandó értéket. MULTISET esetében az alkerdes akárhány sort szolgáltathat, ellenkező esetben csak egyet. TABLE használata esetén lehet fontos, ezért nem nézünk rá példát.
Kollekciómetódusok I. EXISTS(n): igaz értéket ad, ha az n indexű elem létezik a kollekcióban. Ha nem létező indexre hivatkozunk, az EXISTS hamis értéket ad vissza, és nem vált ki kivételt. Minden kollekciótípusra használható. COUNT: visszaadja a kollekció elemeinek számát, minden kollekciótípusra használható. LIMIT: beágyazott tábla esetén a visszatérési értéke NULL, dinamikus tömb esetében a típusdefinícióban megadott maximális méretet adja vissza. FIRST és LAST: a kollekció legelső és legutolsó elemének indexét adják vissza. Ha a kollekció üres, értékük NULL. Dinamikus tömb esetén a FIRST visszatérése 1, a LAST-é COUNT. Minden kollekciótípusra használhatóak. NEXT(n) és PRIOR(n): az n indexű elemet megelőző illetve követő elem indexét adják vissza. Ha ilyen elem nem létezik, értékük NULL. Minden kollekciótípusra használhatóak.
Kollekciómetódusok II. EXTEND[(n[, m])]: paraméter nélkül egyetlen NULL elemet helyez el a végén, EXTEND(n) alakban n db NULL elemet, EXTEND(n,m) alakban pedig az m indexű elem n-szer helyeződik el a kollekció végén. Beágyazott tábla és dinamikus tömb esetén használható. A dinamikus tömb csak a deklarált maximális méretig terjeszthető ki. TRIM(n): a TRIM eltávolítja a kollekció utolsó elemét, TRIM(n) pedig az utolsó n elemét. Ha n > COUNT, akkor SUBSCRIPT_BEYOND_COUNT kivétel váltódik ki. A kollekció mérete a törölt elemek számával csökken. Beágyazott tábla és dinamikus tömb esetén használható. DELETE[(n[, m])]: DELETE törli a kollekció összes elemét, DELETE(n) az n indexű elemet, DELETE(n,m) pedig az n és m indexek közé eső összes elemet. Index alapú tábla és beágyazott tábla esetén használható. A FIRST, LAST, NEXT, PRIOR metódusokkal tetszőleges indexelt tábla vagy beágyazott tábla „bejárható”. Ehhez lásd a 3. példát a Kollekciok_pelda.html fájlban. EXTEND használatához lásd a 4. példát a Kollekciok_pelda.html fájlban.
Együttes hozzárendelés A PL/SQL motor minden procedurális utasítást végrehajt, a beépített SQL utasításokat azonban átadja az SQL motornak. Minden egyes ilyen „motorváltás” növeli a végrehajtás idejét. Különösen igaz ez, ha az SQL utasítás ciklus magjába van ágyazva. A hozzárendelés során egy PL/SQL változónak SQL utasítás segítségével adunk értéket. Együttes hozzárendelés esetén a kollekció minden eleméhez egyszerre rendelődik hozzá érték. Ez nagyban növelheti a teljesítményt.
FORALL I. A PL/SQL oldali együttes hozzárendelés eszköze a FORALL utasítás. Alakja: FORALL index IN also_hatar.. felso_hatar [SAVE EXCEPTIONS] sql_utasitas; Az sql_utasitas INSERT, DELETE vagy UPDATE utasítás, amelyek kollekcióelemet dolgoznak fel. Az SQL-motor az SQL utasítást a megadott indextartomány minden értéke mellett egyszer végrehajtja.
FORALL II. Ha a FORALL utasításban az SQL-utasítás a nem kezelt kivételt vált ki, akkor az egész FORALL visszagörgetődik. Ha viszont a kivételt kezeljük, akkor csak a megkezdett SQL-utasítás görgetődik vissza az utasítás előtt elhelyezett implicit mentési pontig, a korábbi végrehajtások eredményei megmaradnak. A SAVE EXCEPTIONS utasításrész lehetőséget ad, hogy a működés közben kiváltódott kivételeket tároljuk. Új kurzorattribútum: %BULK_EXCEPTIONS, ez rekordok index alapú táblája. Egy-egy rekord két mezeje: %BULK_EXCEPTIONS(i).ERROR_INDEX: a FORALL azon indexe, ahol a kivétel keletkezett, %BULK_EXCEPTIONS(i).ERROR_CODE: a megfelelő hibakód. Az indexek 1-től %BULK_EXCEPTIONS.COUNT-ig mehetnek. Ha nincs SAVE EXCEPTIONS utasításrész, a %BULK_EXCEPTIONS a bekövetkezett kivétel információit tartalmazza.
FORALL III. Az SQL-motor a DML utasításokhoz létrehozza a már említett kurzorattribútumokat (%FOUND, %ISOPEN, %NOTFOUND, %ROWCOUNT). Ezek mellett ebben az esetben használható a %BULK_ROWCOUNT attribútum is. Az i. elem a DML utasítás i. futásánál feldolgozott sorok számát tartalmazza. Értéke 0, ha nem volt ilyen sor.
BULK_COLLECT A SELECT, INSERT, DELETE, UPDATE, FETCH utasítások INTO utasításrészében használható a BULK_COLLECT utasítás, ami az SQL-motortól az együttes hozzárendelést kéri. Alakja: BULK COLLECT INTO kollekcionev [, kollekcionev]… A kollekciók elemtípusainak rendre meg kell egyezniük az eredmény oszlopainak típusaival. Az utasítás mind az implicit, mind az explicit kurzorok esetében használható. Az adatokat a kollekcióban az 1. indextől kezdve helyezi el folyamatosan. FETCH… BULK COLLECT INTO… LIMIT sorok; Itt a sorok egy pozitív számértéket szolgáltató kifejezés, ez korlátozza a betölthető sorok számát.
A két utasítás együtt A FORALL utasítás tartalmazhat olyan INSERT, DELETE, UPDATE utasítást, amelyben szerepel BULK_COLLECT utasítás, de nem tartalmazhat ilyen SELECT utasítást. A FORALL működés közben a BULK_COLLECT által visszaadott eredményeket az egyes iterációk a megelőző iteráció eredményei után fűzik. Ezzel szemben sima FOR ciklus esetén minden iteráció felülírná az előző iteráció eredményeit. A FORALL és a BULK COLLECT utasítás használatához lásd az 5. példát a Kollekciok_pelda.html fájlban.
Feladatok I. Indexelt táblába generáljunk 5 db véletlen számot 1 és 31 között. Írassuk ki azon ugyfelek azonosítóját, nevét és születési dátumát, akik valamelyik napon születtek a fenti 5 nap közül. Ha nincs ilyen ember, váltsuk ki a nincs kivételt és írassuk ki, hogy nincs ilyen ember. Hogyan változik az eljárás, ha indexelt tábla helyett dinamikus tömböt használunk. Írjunk beépített függvényt, amely két mátrix (lásd 3. példa) összegét számolja ki. Az összeadás előtt ellenőrizzük, hogy az összeadandó mátrixok dimenziói a megfelelőek-e. A mai_csod nevű táblában adjuk meg azon részlegek azonosítóját és az ott lévő tartalékot, ahol egy adott napon a részleghez tartozó számlákról több pénzt vettek le, mint amennyi pénz a részleg tartalékát képezi. (A dátum legyen 2007. április 21.)