15. fejezet - A natív dinamikus SQL

Egy PL/SQL kódba (például egy tárolt alprogramba) beágyazhatók SQL utasítások. Ezek ugyanúgy lefordításra kerülnek, mint a procedurális utasítások és futásról futásra ugyanazt a tevékenységet hajtják végre. Ezen utasítások alakja, szövege fordítási időben ismert és utána nem változik meg. Az ilyen utasításokat statikus SQL utasításoknak hívjuk.

A PL/SQL viszont lehetővé teszi azt is, hogy egy SQL utasítás teljes szövege csak futási időben határozódjon meg, tehát futásról futásra változhasson. Ezeket hívjuk dinamikus SQL utasításoknak.

A dinamikus SQL utasítások sztringekben tárolódnak, melyek futási időben kezelhetők. A sztringek tartalma érvényes SQL utasítás vagy PL/SQL blokk lehet, amelyekbe beágyazhatunk ún. helykijelölőket. Ezek nem deklarált azonosítók, melyek első karaktere a kettőspont és a sztring paraméterezésére szolgálnak.

A dinamikus SQL elsősorban akkor használatos, ha

A dinamikus SQL megvalósítására a következő utasítás szolgál:

EXECUTE IMMEDIATE dinamikus_sztring

[INTO {változó [,változó]…|rekord}]

[USING [IN|OUT|IN OUT] kapcsoló_argumentum

[,[IN|OUT|IN OUT] kapcsoló_argumentum]…]

[{RETURNING|RETURN} INTO kapcsoló_argumentum

[,kapcsoló_argumentum]…];

A dinamikus_sztring tartalmazza az SQL utasítást (záró pontosvessző nélkül) vagy a PL/SQL blokkot. A változó egy olyan változó, amely egy leválogatott oszlopot, a rekord pedig egy olyan rekord, amely egy teljes sort tárol. Az INTO utasításrész csak akkor használható, ha a dinamikus_sztring olyan SELECT utasítást tartalmaz, amely egyetlen sort ad vissza. A szolgáltatott sor minden oszlopához meg kell adni típuskompatibilis változót, vagy pedig a rekordban léteznie kell egy ilyen mezőnek.

A dinamikus_sztring az utasítás fenti formájában nem tartalmazhat több sort visszaadó kérdést. Az ilyen kérdés dinamikus végrehajtására az OPEN–FOR, FETCH, CLOSE utasításokat vagy együttes hozzárendelést használunk. Ezeket a fejezet későbbi részében tárgyaljuk.

A USING utasításrész input (IN – ez az alapértelmezés), output (OUT) vagy input-output (IN OUT) kapcsoló_argumentumokat határozhat meg. Ezek IN esetén olyan kifejezések lehetnek, amelyek értéke átkerül a helykijelölőbe. OUT és IN OUT esetén pedig ezek változók, amelyek tárolják az SQL utasítás vagy blokk által szolgáltatott értékeket. A helykijelölők és a kapcsoló argumentumok számának meg kell egyezni (kivéve ha a DML utasításnál szerepel a RETURNING utasításrész), egymáshoz rendelésük a sorrend alapján történik. A kapcsoló_argumentum típusa nem lehet speciális PL/SQL típus (például BOOLEAN). NULL érték a kapcsoló_argumentummal nem adható át, de egy NULL értékű változóval

igen.

A RETURNING INTO utasításrész olyan dinamikus DML utasítások esetén használható, amelyek RETURNING utasításrészt tartalmaznak (BULK COLLECT utasításrész nélkül). Ez az utasításrész határozza meg azokat a kapcsoló változókat, amelyek a DML utasítás által visszaadott értékeket tárolják. A DML utasítás által szolgáltatott minden értékhez meg kell adni egy típuskompatibilis kapcsoló_argumentumot. Ebben az esetben a USING utasításrészben nem lehet OUT vagy IN OUT kapcsoló_argumentum.

Az EXECUTE IMMEDIATE utasítás minden végrehajtásánál a dinamikus_sztring tartalma elemzésre, majd végrehajtásra kerül.

A következő példák a fejezet végén szereplő notesz csomagból valók, és speciálisan az EXECUTE IMMEDIATE utasítás egy-egy tulajdonságát emelik ki:

1. példa (DDL használata és a sémaobjektum nevének dinamikus meghatározása)

PROCEDURE tabla_letrehoz

IS

BEGIN

EXECUTE IMMEDIATE 'CREATE TABLE ' || v_Sema || '.notesz_feljegyzesek ('

|| 'idopont DATE NOT NULL,'

|| 'szemely VARCHAR2(20) NOT NULL,'

|| 'szoveg VARCHAR2(3000),'

|| 'torles_ido DATE'

|| ')';

END tabla_letrehoz;

2. példa (Az implicit kurzorattribútumok használhatók a dinamikus SQL-lel)

FUNCTION torol_lejart

RETURN NUMBER IS

BEGIN

EXECUTE IMMEDIATE 'DELETE FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE torles_ido < SYSDATE';

RETURN SQL%ROWCOUNT;

END torol_lejart;

3. példa (A USING és RETURNING használata)

EXECUTE IMMEDIATE 'INSERT INTO ' || v_Sema || '.notesz_feljegyzesek '

|| 'VALUES (:1, :2, :3, :4) '

|| 'RETURNING idopont, szemely, szoveg, torles_ido '

|| 'INTO :5, :6, :7, :8 '

USING p_Idopont, p_Szemely, p_Szoveg, p_Torles_ido

RETURNING INTO rv.idopont, rv.szemely, rv.szoveg, rv.torles_ido;

4. példa (Az INTO használata)

EXECUTE IMMEDIATE 'SELECT MIN(idopont) '

|| 'FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE idopont > :idopont '

INTO p_Datum

USING p_Datum;

Több sort szolgáltató kérdések dinamikus feldolgozása

A dinamikus SQL használatánál is kurzorváltozót kell alkalmazni, ha több sort visszaadó SELECT utasítást akarunk kezelni (a kurzorokkal kapcsolatban lásd 8. fejezet).

A dinamikus OPEN–FOR utasítás egy kurzorváltozóhoz hozzárendel egy dinamikus lekérdezést, lefuttatja azt, meghatározza az aktív halmazt, a kurzort az első sorra állítja és nullázza a %ROWCOUNT attribútumot. Alakja:

OPEN kurzorváltozó FOR dinamikus_sztring

[USING kapcsoló_argumentum [,kapcsoló_argumentum]…];

Az utasításrészek jelentése ugyanaz, mint amit fentebb tárgyaltunk.

1. példa

FUNCTION feljegyzesek(

p_Idopont v_Feljegyzes.idopont%tyPE DEfAULT SYSDATE,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT NULL

) RETURN t_refcursor IS

rv t_refcursor;

BEGIN

OPEN rv FOR

'SELECT * FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE idopont BETWEEN :idopont AND :idopont + 1 '

|| 'AND (:szemely IS NULL OR szemely = :szemely) '

|| 'ORDER BY idopont'

USING TRUNC(p_Idopont), TRUNC(p_Idopont), p_Szemely, p_Szemely;

RETURN rv;

END feljegyzesek;

A betöltés és lezárás ugyanúgy történik, mint statikus esetben.

2. példa

-- az előző példa függvényével megnyitjuk a kurzort

v_Feljegyzesek_cur := feljegyzesek(p_Idopont, p_Szemely);

LOOP

FETCH v_Feljegyzesek_cur INTO v_Feljegyzes;

EXIT WHEN v_Feljegyzesek_cur%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(v_Feljegyzesek_cur%ROWCOUNT || '. '

|| TO_CHAR(v_Feljegyzes.idopont, 'HH24:MI') || ', '

|| v_Feljegyzes.szemely || ', ' || v_Feljegyzes.szoveg || ', '

|| TO_CHAR(v_Feljegyzes.torles_ido, 'YYYY-MM-DD HH24:MI'));

END LOOP;

CLOSE v_Feljegyzesek_cur;

Dinamikus együttes hozzárendelés

Az együttes hozzárendelés statikus verzióját a 12. fejezetben tárgyaltuk. Nézzük, hogyan alkalmazható dinamikus esetben. Az együttes EXECUTE IMMEDIATE utasítás alakja:

EXECUTE IMMEDIATE dinamikus_sztring

[BULK COLLECT INTO változó[,változó]…]

[USING kapcsoló_argumentum[,kapcsoló_argumentum]…]

[{RETURNING|RETURN}

BULK COLLECT INTO kapcsoló_argumentum[,kapcsoló_argumentum]…];

Egy dinamikus, több sort szolgáltató lekérdezés eredménye a BULK COLLECT INTO utasításrész segítségével úgy kezelhető, hogy az oszlopok értékei egy-egy kollekcióban vagy egy megfelelő rekord elemtípusú kollekcióban kerülnek tárolásra. A több sort visszaadó dinamikus INSERT, DELETE, UPDATE esetén RETURNING BULK COLLECT INTO definiálja az outputot fogadó kollekciókat.

Az együttes FETCH alakja:

FETCH dinamikus_kurzor

BULK COLLECT INTO változó[,változó]…;

Lehetőség van arra, hogy a FORALL (lásd 12. fejezet) ciklus belsejében alkalmazzuk az EXECUTE IMMEDIATE utasítást, ha az nem tartalmaz SELECT utasítást. Ennek alakja:

FORALL index IN alsó_határ..felső_határ

EXECUTE IMMEDIATE dinamikus_sztring

USING kapcsoló_argumentum[(index)]

[,kapcsoló_argumentum[(index)]]…

[{RETURNING|RETURN} BULK COLLECT INTO

kapcsoló_argumentum[,kapcsoló_argumentum]…];

1. példa (BULK COLLECT használata)

EXECUTE IMMEDIATE

'SELECT szemely, COUNT(1) '

|| 'FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE idopont BETWEEN '

|| 'TO_DATE(''' || v_Ido || ''', ''YYYY-MM-DD'') '

|| 'AND TO_DATE(''' || v_Ido || ''', ''YYYY-MM-DD'') + 1 '

|| v_Szemely_pred

|| 'GROUP BY szemely'

BULK COLLECT INTO p_Nevek, p_Szamok;

2. példa (FORALL és %BULK_ROWCOUNT)

FORALL i IN 1..p_Szemely_lista.COUNT

EXECUTE IMMEDIATE 'DELETE FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE szemely = :szemely'

USING p_Szemely_lista(i);

p_Szam_lista := t_szam_lista();

p_Szam_lista.EXTEND(p_Szemely_lista.COUNT);

FOR i IN 1..p_Szam_lista.COUNT LOOP

p_Szam_lista(i) := SQL%BULK_ROWCOUNT(i);

END LOOP;

A dinamikus SQL használata – esettanulmány

A következő esettanulmány egy noteszt létrehozó és kezelő csomag, mely a PL/SQL számos eszközét felvonultatja, de talán a legfontosabb azt kiemelni, hogy a csomag az aktuális hívó jogosultságaival fut és natív dinamikus SQL-t használ. A csomag specifikációja a következő:

CREATE OR REPLACE PACKAGE notesz

AUTHID CURRENT_USER

/*

A csomag segítségével időpontokhoz és

személyekhez kötött feljegyzéseket

készíthetünk és kezelhetünk.

A csomag képes létrehozni a szükséges táblákat

natív dinamikus SQL segítségével, mivel a

csomag eljárásai a hívó jogosultságaival futnak le.

*/

AS

/************************************************/

/* A csomag által nyújtott típusok, deklarációk */

/************************************************/

-- Egy feljegyzés formátuma

TYPE t_feljegyzes IS RECORD(

idopont DATE,

szemely VARCHAR2(20),

szoveg VARCHAR2(3000),

torles_ido DATE

);

-- Egy általános REF CURSOR

TYPE t_refcursor IS REF CURSOR;

-- Egy feljegyzes rekord, a %TYPE-okhoz

v_Feljegyzes t_feljegyzes;

-- Kollekciótípusok

TYPE t_feljegyzes_lista IS TABLE OF t_feljegyzes;

TYPE t_szemely_lista IS TABLE OF v_Feljegyzes.szemely%TYPE;

TYPE t_szam_lista IS TABLE OF NUMBER;

-- A hibás argumentum esetén az alprogramok kiválthatják

-- a hibas_argumentum kivételt.

hibas_argumentum EXCEPTION;

PRAGMA EXCEPTION_INIT(hibas_argumentum, -20200);

/******************************************/

/* A csomag által nyújtott szolgáltatások */

/******************************************/

-- A használt séma nevét állíthatjuk át

PROCEDURE init_sema(p_Sema VARCHAR2 DEFAULT USER);

-- Létrehozza a táblát az aktuális sémában

PROCEDURE tabla_letrehoz;

-- Törli a táblát az aktuális sémában

PROCEDURE tabla_torol;

-- Bejegyez egy feljegyzést és visszaadja egy rekordban

FUNCTION feljegyez(

p_Idopont v_Feljegyzes.idopont%TYPE,

p_Szoveg v_Feljegyzes.szoveg%TYPE,

p_Torles_ido v_Feljegyzes.torles_ido%TYPE DEFAULT NULL,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT USER

) RETURN t_feljegyzes;

-- Megnyitja és visszaadja az adott személy feljegyzéseit a

-- napra. Ha a szemely NULL, akkor az összes feljegyzést megadja.

FUNCTION feljegyzesek(

p_Idopont v_Feljegyzes.idopont%tyPE DEfAULT SYSDATE,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT NULL

) RETURN t_refcursor;

-- Visszaadja egy táblában az adott személy feljegyzéseinek számát a

-- napra. Ekkor p_Nevek és p_Szamok egy-egy elemet tartalmaznak.

-- Ha a p_Szemely NULL, akkor az összes feljegyzést visszadja a napra,

-- p_Nevek és p_Szamok megegyező elemszámúak lesznek.

PROCEDURE feljegyzes_lista(

p_Nevek OUT NOCOPY t_szemely_lista,

p_Szamok OUT NOCOPY t_szam_lista,

p_Idopont v_Feljegyzes.idopont%TYPE DEFAULT SYSDATE,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT NULL

);

-- Kilistázza az adott személy feljegyzéseit a

-- napra. Ha a szemely NULL, akkor az összes feljegyzést megadja.

PROCEDURE feljegyzesek_listaz (

p_Idopont v_Feljegyzes.idopont%TYPE DEFAULT SYSDATE,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT NULL

);

-- Megadja az időben első feljegyzés időpontját

PROCEDURE elso_feljegyzes(

p_Datum OUT DATE

);

-- A paraméterben megadja az első olyan feljegyzés időpontját,

-- amely időpontja nagyobb, mint a p_Datum.

-- NULL-t ad vissza, ha nincs ilyen.

PROCEDURE kovetkezo_feljegyzes(

p_Datum IN OUT DATE

);

-- Megadja az időben utolsó feljegyzés időpontját

PROCEDURE utolso_feljegyzes(

p_Datum OUT DATE

);

-- A paraméterben megadja az első olyan feljegyzés időpontját,

-- amely időpontja kisebb, mint a p_Datum.

-- NULL-t ad vissza, ha nincs ilyen.

PROCEDURE elozo_feljegyzes(

p_Datum IN OUT DATE

);

-- Törli a törlési idővel megjelölt és lejárt feljegyzéseket és

-- visszaadja a törölt elemek számát.

FUNCTION torol_lejart RETURN NUMBER;

-- Törli a megadott személyek összes feljegyzéseit és visszaadja

-- az egyes ügyfelekhez a törölt elemek számát.

PROCEDURE feljegyzesek_torol (

p_Szemely_lista t_szemely_lista,

p_Szam_lista OUT NOCOPY t_szam_lista

);

END notesz;

/

show errors

A csomag törzse:

CREATE OR REPLACE PACKAGE BODY notesz

AS

/**********************/

/* Privát deklarációk */

/**********************/

-- A séma nevét tárolja

v_Sema VARCHAR2(30);

/***************************************/

/* Publikus deklarációk implementációi */

/***************************************/

-- A használt séma nevét állíthatjuk át

PROCEDURE init_sema(p_Sema VARCHAR2 DEFAULT USER) IS

BEGIN

v_Sema := p_Sema;

END init_sema;

-- Létrehozza a táblát az aktuális sémában

PROCEDURE tabla_letrehoz

IS

BEGIN

EXECUTE IMMEDIATE 'CREATE TABLE ' || v_Sema || '.notesz_feljegyzesek ('

|| 'idopont DATE NOT NULL,'

|| 'szemely VARCHAR2(20) NOT NULL,'

|| 'szoveg VARCHAR2(3000),'

|| 'torles_ido DATE'

|| ')';

END tabla_letrehoz;

-- Törli a táblát az aktuális sémában

PROCEDURE tabla_torol

IS

BEGIN

EXECUTE IMMEDIATE 'DROP TABLE ' || v_Sema || '.notesz_feljegyzesek';

END tabla_torol;

-- Bejegyez egy feljegyzést és visszaadja egy rekordban

FUNCTION feljegyez(

p_Idopont v_Feljegyzes.idopont%TYPE,

p_Szoveg v_Feljegyzes.szoveg%TYPE,

p_Torles_ido v_Feljegyzes.torles_ido%TYPE DEFAULT NULL,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT USER

) RETURN t_feljegyzes

IS

rv t_feljegyzes;

BEGIN

IF p_Idopont IS NULL THEN

RAISE_APPLICATION_ERROR(-20200,

'Nem lehet NULL az időpont egy feljegyzésben');

END IF;

EXECUTE IMMEDIATE 'INSERT INTO ' || v_Sema || '.notesz_feljegyzesek '

|| 'VALUES (:1, :2, :3, :4) '

|| 'RETURNING idopont, szemely, szoveg, torles_ido '

|| 'INTO :5, :6, :7, :8 '

USING p_Idopont, p_Szemely, p_Szoveg, p_Torles_ido

RETURNING INTO rv.idopont, rv.szemely, rv.szoveg, rv.torles_ido;

/* A RETURNING helyett lehetne a USING-ot is használni:

USING ...,

OUT rv.idopont, OUT rv.szemely, OUT rv.szoveg, OUT rv.torles_ido;

Az Oracle azonban a RETURNING használatát javasolja.

*/

RETURN rv;

END feljegyez;

-- Megnyitja és visszaadja az adott személy feljegyzéseit a

-- napra. Ha a szemely NULL, akkor az összes feljegyzést megadja.

FUNCTION feljegyzesek(

p_Idopont v_Feljegyzes.idopont%tyPE DEfAULT SYSDATE,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT NULL

) RETURN t_refcursor IS

rv t_refcursor;

BEGIN

OPEN rv FOR

'SELECT * FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE idopont BETWEEN :idopont AND :idopont + 1 '

|| 'AND (:szemely IS NULL OR szemely = :szemely) '

|| 'ORDER BY idopont'

USING TRUNC(p_Idopont), TRUNC(p_Idopont), p_Szemely, p_Szemely;

RETURN rv;

END feljegyzesek;

-- Visszaadja egy táblában az adott személy feljegyzéseinek számát a

-- napra. Ekkor p_Nevek és p_Szamok egy-egy elemet tartalmaznak.

-- Ha a p_Szemely NULL, akkor az összes feljegyzést visszadja a napra,

-- p_Nevek és p_Szamok megegyező elemszámúak lesznek.

PROCEDURE feljegyzes_lista(

p_Nevek OUT NOCOPY t_szemely_lista,

p_Szamok OUT NOCOPY t_szam_lista,

p_Idopont v_Feljegyzes.idopont%TYPE DEFAULT SYSDATE,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT NULL

) IS

v_Ido VARCHAR2(10);

v_Szemely_pred VARCHAR2(100);

v_Datum DATE;

BEGIN

v_Ido := TO_CHAR(p_Idopont, 'YYYY-MM-DD');

v_Szemely_pred := CASE

WHEN p_Szemely IS NULL THEN ''

ELSE 'AND ''' || p_Szemely || ''' = szemely '

END;

EXECUTE IMMEDIATE

'SELECT szemely, COUNT(1) '

|| 'FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE idopont BETWEEN '

|| 'TO_DATE(''' || v_Ido || ''', ''YYYY-MM-DD'') '

|| 'AND TO_DATE(''' || v_Ido || ''', ''YYYY-MM-DD'') + 1 '

|| v_Szemely_pred

|| 'GROUP BY szemely'

BULK COLLECT INTO p_Nevek, p_Szamok;

END feljegyzes_lista;

-- Kilistázza az adott személy feljegyzéseit a

-- napra. Ha a szemely NULL, akkor az összes feljegyzést megadja.

PROCEDURE feljegyzesek_listaz(

p_Idopont v_Feljegyzes.idopont%TYPE DEFAULT SYSDATE,

p_Szemely v_Feljegyzes.szemely%TYPE DEFAULT NULL

) IS

v_Feljegyzesek_cur t_refcursor;

v_Feljegyzes t_feljegyzes;

BEGIN

v_Feljegyzesek_cur := feljegyzesek(p_Idopont, p_Szemely);

LOOP

FETCH v_Feljegyzesek_cur INTO v_Feljegyzes;

EXIT WHEN v_Feljegyzesek_cur%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(v_Feljegyzesek_cur%ROWCOUNT || '. '

|| TO_CHAR(v_Feljegyzes.idopont, 'HH24:MI') || ', '

|| v_Feljegyzes.szemely || ', ' || v_Feljegyzes.szoveg || ', '

|| TO_CHAR(v_Feljegyzes.torles_ido, 'YYYY-MM-DD HH24:MI'));

END LOOP;

CLOSE v_Feljegyzesek_cur;

END feljegyzesek_listaz;

-- Megadja az időben első feljegyzés időpontját

PROCEDURE elso_feljegyzes(

p_Datum OUT DATE

) IS

BEGIN

EXECUTE IMMEDIATE 'SELECT MIN(idopont) '

|| 'FROM ' || v_Sema || '.notesz_feljegyzesek'

INTO p_Datum;

END elso_feljegyzes;

-- A paraméterben megadja az első olyan feljegyzés időpontját,

-- amely időpont nagyobb, mint a p_Datum.

-- NULL-t ad vissza, ha nincs ilyen.

PROCEDURE kovetkezo_feljegyzes(

p_Datum IN OUT DATE

) IS

BEGIN

EXECUTE IMMEDIATE 'SELECT MIN(idopont) '

|| 'FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE idopont > :idopont '

INTO p_Datum

USING p_Datum;

END kovetkezo_feljegyzes;

-- Megadja az időben utolsó feljegyzés időpontját

PROCEDURE utolso_feljegyzes(

p_Datum OUT DATE

) IS

BEGIN

EXECUTE IMMEDIATE 'SELECT MAX(idopont) '

|| 'FROM ' || v_Sema || '.notesz_feljegyzesek'

INTO p_Datum;

END utolso_feljegyzes;

-- A paraméterben megadja az első olyan feljegyzés időpontját,

-- amely időpontja kisebb, mint a p_Datum.

-- NULL-t ad vissza, ha nincs ilyen.

PROCEDURE elozo_feljegyzes(

p_Datum IN OUT DATE

) IS

BEGIN

EXECUTE IMMEDIATE 'SELECT MAX(idopont) '

|| 'FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE idopont < :idopont '

INTO p_Datum

USING p_Datum;

END elozo_feljegyzes;

-- Törli a törlési idővel megjelölt és lejárt feljegyzéseket és

-- visszaadja a törölt elemek számát.

FUNCTION torol_lejart

RETURN NUMBER IS

BEGIN

EXECUTE IMMEDIATE 'DELETE FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE torles_ido < SYSDATE';

RETURN SQL%ROWCOUNT;

END torol_lejart;

-- Törli a megadott személyek összes feljegyzéseit és visszaadja

-- az egyes ügyfelekhez a törölt elemek számát.

PROCEDURE feljegyzesek_torol(

p_Szemely_lista t_szemely_lista,

p_Szam_lista OUT NOCOPY t_szam_lista

) IS

BEGIN

FORALL i IN 1..p_Szemely_lista.COUNT

EXECUTE IMMEDIATE 'DELETE FROM ' || v_Sema || '.notesz_feljegyzesek '

|| 'WHERE szemely = :szemely'

USING p_Szemely_lista(i);

p_Szam_lista := t_szam_lista();

p_Szam_lista.EXTEND(p_Szemely_lista.COUNT);

FOR i IN 1..p_Szam_lista.COUNT LOOP

p_Szam_lista(i) := SQL%BULK_ROWCOUNT(i);

END LOOP;

END feljegyzesek_torol;

/**************************/

/* Csomag inicializációja */

/**************************/

BEGIN

init_sema;

END notesz;

/

show errors

Példaprogram a csomag használatára:

DECLARE

v_Datum DATE;

v_Szam NUMBER;

v_Feljegyzes notesz.t_feljegyzes;

v_Feljegyzes_lista notesz.t_feljegyzes_lista;

v_Feljegyzesek_cur notesz.t_refcursor;

v_Nevek notesz.t_szemely_lista;

v_Szamok notesz.t_szam_lista;

BEGIN

BEGIN

notesz.tabla_torol;

EXCEPTION

WHEN OTHERS THEN

DBMS_OUTPUT.PUT_LINE('Nem volt még ilyen tábla.');

END;

notesz.tabla_letrehoz;

v_Feljegyzes := notesz.feljegyez(SYSDATE - 1, 'Mi volt ?', SYSDATE - 0.0001);

v_Feljegyzes := notesz.feljegyez(SYSDATE, 'Mi van ?');

v_Feljegyzes := notesz.feljegyez(SYSDATE+0.02, 'Mi van haver?',

p_Szemely => 'HAVER');

v_Feljegyzes := notesz.feljegyez(SYSDATE+0.05, 'Mi van haver megint?',

SYSDATE-0.05, 'HAVER');

v_Feljegyzes := notesz.feljegyez(SYSDATE + 1, 'Mi lesz ?');

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Kurzor teszt:');

v_Feljegyzesek_cur := notesz.feljegyzesek(p_Szemely => 'HAVER');

LOOP

FETCH v_Feljegyzesek_cur INTO v_Feljegyzes;

EXIT WHEN v_Feljegyzesek_cur%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(v_Feljegyzesek_cur%ROWCOUNT || ', '

|| v_Feljegyzes.szoveg);

END LOOP;

CLOSE v_Feljegyzesek_cur;

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Lista teszt:');

notesz.feljegyzes_lista(v_Nevek, v_Szamok);

FOR i IN 1..v_Nevek.COUNT LOOP

DBMS_OUTPUT.PUT_LINE(i || ', ' || v_Nevek(i) || ': ' || v_Szamok(i));

END LOOP;

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Listázó teszt:');

notesz.feljegyzesek_listaz;

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Idő növekvő:');

notesz.elso_feljegyzes(v_Datum);

WHILE v_Datum IS NOT NULL LOOP

DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_Datum, 'YYYY-MON-DD HH24:MI'));

notesz.kovetkezo_feljegyzes(v_Datum);

END LOOP;

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Idő csökkenő:');

notesz.utolso_feljegyzes(v_Datum);

WHILE v_Datum IS NOT NULL LOOP

DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_Datum, 'YYYY-MON-DD HH24:MI'));

notesz.elozo_feljegyzes(v_Datum);

END LOOP;

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Lejárt teszt:');

v_Szam := notesz.torol_lejart;

DBMS_OUTPUT.PUT_LINE('Törölt elemek száma: ' || v_Szam);

EXECUTE IMMEDIATE 'SELECT COUNT(1) FROM notesz_feljegyzesek'

INTO v_Szam;

DBMS_OUTPUT.PUT_LINE('Ennyi maradt: ' || v_Szam);

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Törlés teszt:');

v_Nevek := notesz.t_szemely_lista('HAVER', 'Haha', 'PLSQL');

notesz.feljegyzesek_torol(v_Nevek, v_Szamok);

FOR i IN 1..v_Nevek.COUNT LOOP

DBMS_OUTPUT.PUT_LINE(i || ', ' || v_Nevek(i) || ': ' || v_Szamok(i));

END LOOP;

EXECUTE IMMEDIATE 'SELECT COUNT(1) FROM notesz_feljegyzesek'

INTO v_Szam;

DBMS_OUTPUT.NEW_LINE;

DBMS_OUTPUT.PUT_LINE('Ennyi maradt: ' || v_Szam);

DBMS_OUTPUT.PUT_LINE('Vége.');

END;

/

/*

Eredmény:

Kurzorteszt:

1, Mi van haver?

2, Mi van haver megint?

Listateszt:

1, PLSQL: 1

2, HAVER: 2

Listázóteszt:

1, 02:27, PLSQL, Mi van?,

2, 02:56, HAVER, Mi van haver?,

3, 03:39, HAVER, Mi van haver megint?, 2006-06-23 01:15

Idő növekvő:

2006-JÚN. -22 02:27

2006-JÚN. -23 02:27

2006-JÚN. -23 02:56

2006-JÚN. -23 03:39

2006-JÚN. -24 02:27

Idő csökkenő:

2006-JÚN. -24 02:27

2006-JÚN. -23 03:39

2006-JÚN. -23 02:56

2006-JÚN. -23 02:27

2006-JÚN. -22 02:27

Lejárt teszt:

Törölt elemek száma: 2

Ennyi maradt: 3

Törlés teszt:

1, HAVER: 1

2, Haha: 0

3, PLSQL: 2

Ennyi maradt: 0

Vége.

A PL/SQL eljárás sikeresen befejeződött.

*/