Az objektumtípusú kollekciók esetén a PL/SQL implicit módon metódusokat definiál a kezelésükhöz. Ezen metódusok egy része asszociatív tömb esetén is használható. Ezek a metódusok csak procedurális utasításokban hívhatók, SQL utasításokban nem.
A metódusok áttekintését szolgálja a 12.2. táblázat.
12.2. táblázat - Kollekciómetódusok
Metódus |
Visszatérési típus |
Tevékenység |
Kollekció |
EXISTS |
BOOLEAN |
Igaz értéket ad, ha az adott indexű elem létezik a kollekcióban. |
Minden kollekció |
COUNT |
NUMBER |
Visszaadja a kollekció elemeinek számát. |
Minden kollekció |
LIMIT |
NUMBER |
Visszaadja a kollekció maximális méretét. |
Minden kollekció |
FIRST |
indextípus |
Visszaadja a kollekció első elemének indexét. |
Minden kollekció |
LAST |
indextípus |
Visszaadja a kollekció utolsó elemének indexét. |
Minden kollekció |
NEXT |
indextípus |
Visszaadja egy megadott indexű elemet követő elem indexét. |
Minden kollekció |
PRIOR |
indextípus |
Visszaadja egy megadott indexű elemet megelőző elem indexét. |
Minden kollekció |
EXTEND |
nincs |
Bővíti a kollekciót. |
Beágyazott tábla, dinamikus tömb |
TRIM |
nincs |
Eltávolítja a kollekció utolsó elemeit. |
Beágyazott tábla, dinamikus tömb |
DELETE |
nincs |
A megadott elemeket törli a kollekcióból. |
Asszociatív tömb, beágyazott tábla, dinamikus tömb esetén csak paraméter nélkül |
Az egyes metódusokat a következőkben részletezzük.
EXISTS
Alakja
EXISTS(i)
ahol i egy az index típusának megfelelő kifejezés.
Igaz értéket ad, ha az i indexű elem létezik a kollekcióban, egyébként hamisat. Ha nem létező indexre hivatkozunk, az EXISTS hamis értékkel tér vissza és nem vált ki kivételt.
Az EXISTS az egyetlen metódus, amely nem inicializált beágyazott táblára és dinamikus tömbre is meghívható (ekkor hamis értékkel tér vissza), az összes többi metódus ekkor a COLLECTION_IS_NULL kivételt váltja ki.
Az EXISTS használatával elkerülhető, hogy nem létező elemre hivatkozzunk és ezzel kivételt váltsunk ki.
1. példa
DECLARE
v_Szerzok T_Szerzok;
i PLS_INTEGER;
BEGIN
SELECT szerzo
INTO v_Szerzok
FROM konyv
WHERE id = 15;
i := 1;
WHILE v_Szerzok.EXISTS(i) LOOP
DBMS_OUTPUT.PUT_LINE(v_Szerzok(i));
i := i+1;
END LOOP;
END;
/
/* Eredmény:
P. Howard
Rejtő Jenő
A PL/SQL eljárás sikeresen befejeződött.
*/
2. példa
DECLARE
TYPE t_vektor IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
v_Vektor t_vektor;
BEGIN
FOR i IN -2..2 LOOP
v_Vektor(i*2) := i;
END LOOP;
FOR i IN -5..5 LOOP
IF v_Vektor.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(LPAD(i,2) || ' '
|| LPAD(v_Vektor(i), 2));
END IF;
END LOOP;
END;
/
/* Eredmény:
-4 -2
-2 -1
0 0
2 1
4 2
A PL/SQL eljárás sikeresen befejeződött.
*/
3. példa
DECLARE
TYPE t_tablazat IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
v_Tablazat t_tablazat;
v_Kulcs VARCHAR2(10);
BEGIN
FOR i IN 65..67 LOOP
v_Kulcs := CHR(i);
v_Tablazat(v_Kulcs) := i;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Kulcs Elem');
DBMS_OUTPUT.PUT_LINE('----- ----');
FOR i IN 0..255 LOOP
v_Kulcs := CHR(i);
IF v_Tablazat.EXISTS(v_Kulcs) THEN
DBMS_OUTPUT.PUT_LINE(RPAD(v_Kulcs, 7) || v_Tablazat(v_Kulcs));
END IF;
END LOOP;
END;
/
/* Eredmény:
Kulcs Elem
----- ----
A 65
B 66
C 67
A PL/SQL eljárás sikeresen befejeződött.
*/
COUNT
Paraméter nélküli függvény. Megadja a kollekció aktuális (nem törölt) elemeinek számát. Dinamikus tömb esetén visszatérési értéke azonos a LAST visszatérési értékével, a többi kollekciónál ez nem feltétlenül van így.
1. példa
DECLARE
v_Szerzok T_Szerzok;
BEGIN
SELECT szerzo
INTO v_Szerzok
FROM konyv
WHERE id = 15;
FOR i IN 1..v_Szerzok.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_Szerzok(i));
END LOOP;
END;
/
/* Eredmény:
P. Howard
Rejtő Jenő
A PL/SQL eljárás sikeresen befejeződött.
*/
2. példa
DECLARE
TYPE t_vektor IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
v_Vektor t_vektor;
BEGIN
FOR i IN -2..2 LOOP
v_Vektor(i*2) := i;
END LOOP;
DBMS_OUTPUT.PUT_LINE(v_Vektor.COUNT);
END;
/
/* Eredmény:
5
A PL/SQL eljárás sikeresen befejeződött.
*/
LIMIT
Paraméter nélküli függvény. Beágyazott tábla és asszociatív tömb esetén visszatérési értéke NULL. Dinamikus tömb esetén a típusdefinícióban megadott maximális méretet adja.
Példa
DECLARE
v_Szerzok T_Szerzok;
v_Konyvek T_Konyvek;
BEGIN
SELECT szerzo INTO v_Szerzok FROM konyv WHERE id = 15;
SELECT konyvek INTO v_Konyvek FROM ugyfel WHERE id = 10;
DBMS_OUTPUT.PUT_LINE('1. szerzo count: ' || v_Szerzok.COUNT
|| ' Limit: ' || NVL(TO_CHAR(v_Szerzok.LIMIT), 'NULL'));
DBMS_OUTPUT.PUT_LINE('2. konyvek count: ' || v_Konyvek.COUNT
|| ' Limit: ' || NVL(TO_CHAR(v_Konyvek.LIMIT), 'NULL'));
END;
/
/* Eredmény:
1. szerzo count: 2 Limit: 10
2. konyvek count: 3 Limit: NULL
A PL/SQL eljárás sikeresen befejeződött.
*/
FIRST és LAST
Paraméter nélküli függvények. A FIRST a kollekció legelső (nem törölt) elemének indexét (a kollekció legkisebb indexét), a LAST a legutolsó (nem törölt) elem indexét (a kollekció legnagyobb indexét) adja vissza. Ha a kollekció üres, akkor értékük NULL. Dinamikus tömbnél a FIRST visszatérési értéke 1, a LAST-é COUNT.
VARCHAR2 típusú kulccsal rendelkező asszociatív tömbnél a legkisebb és legnagyobb kulcsértéket adják meg. Ha az NLS_COMP inicializációs paraméter értéke ANSI, akkor a kulcsok rendezési sorrendjét az NLS_SORT inicializációs paraméter határozza meg.
1. példa
DECLARE
v_Szerzok T_Szerzok;
j PLS_INTEGER;
BEGIN
BEGIN
j := v_Szerzok.FIRST;
EXCEPTION
WHEN COLLECTION_IS_NULL THEN
DBMS_OUTPUT.PUT_LINE('Kivétel! ' || SQLERRM);
END;
v_Szerzok := T_Szerzok();
DBMS_OUTPUT.PUT_LINE('first: '
|| NVL(TO_CHAR(v_Szerzok.FIRST), 'NULL')
|| ' last: ' || NVL(TO_CHAR(v_Szerzok.LAST), 'NULL'));
DBMS_OUTPUT.NEW_LINE;
SELECT szerzo
INTO v_Szerzok
FROM konyv
WHERE id = 15;
FOR i IN v_Szerzok.FIRST..v_Szerzok.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_Szerzok(i));
END LOOP;
END;
/
/* Eredmény:
Kivétel! ORA-06531: Inicializálatlan gyűjtőre való hivatkozás
first: NULL last: NULL
P. Howard
Rejtő Jenő
A PL/SQL eljárás sikeresen befejeződött.
*/
2. példa
DECLARE
TYPE t_vektor IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
v_Vektor t_vektor;
BEGIN
FOR i IN -2..2 LOOP
v_Vektor(i*2) := i;
END LOOP;
DBMS_OUTPUT.PUT_LINE('first: '
|| NVL(TO_CHAR(v_Vektor.FIRST), 'NULL')
|| ' last: ' || NVL(TO_CHAR(v_Vektor.LAST), 'NULL'));
END;
/
/* Eredmény:
first: -4 last: 4
A PL/SQL eljárás sikeresen befejeződött.
*/
NEXT és PRIOR
Alakjuk:
NEXT(i)
PRIOR(i)
ahol i az index típusának megfelelő kifejezés.
A NEXT visszaadja az i indexű elemet követő (nem törölt), a PRIOR a megelőző (nem törölt) elem indexét. Ha ilyen elem nem létezik, értékük NULL.
VARCHAR2 típusú kulccsal rendelkező asszociatív tömbnél a sztringek rendezettségének megfelelő következő és megelőző kulcsértéket adják meg. Ha az NLS_COMP inicializációs paraméter értéke ANSI, akkor a kulcsok rendezési sorrendjét az NLS_SORT inicializációs paraméter határozza meg.
A FIRST, LAST, NEXT, PRIOR alkalmas arra, hogy bármely kollekció aktuális elemeit növekvő vagy csökkenő indexek szerint feldolgozzuk.
1. példa
DECLARE
TYPE t_vektor IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
v_Vektor t_vektor;
i PLS_INTEGER;
BEGIN
FOR i IN -2..2 LOOP
v_Vektor(i*2) := i;
END LOOP;
i := v_Vektor.FIRST;
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(LPAD(i,2) || ' '
|| LPAD(v_Vektor(i), 2));
i := v_Vektor.NEXT(i);
END LOOP;
DBMS_OUTPUT.NEW_LINE;
i := v_Vektor.LAST;
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(LPAD(i,2) || ' '
|| LPAD(v_Vektor(i), 2));
i := v_Vektor.PRIOR(i);
END LOOP;
END;
/
/*
Eredmény:
-4 -2
-2 -1
0 0
2 1
4 2
4 2
2 1
0 0
-2 -1
-4 -2
A PL/SQL eljárás sikeresen befejeződött.
*/
2. példa
CREATE OR REPLACE PROCEDURE elofordulasok(p_Szoveg VARCHAR2) IS
c VARCHAR2(1 CHAR);
TYPE t_gyakorisag IS TABLE OF NUMBER INDEX BY c%TYPE;
v_Elofordulasok t_gyakorisag;
BEGIN
FOR i IN 1..LENGTH(p_Szoveg) LOOP
c := LOWER(SUBSTR(p_Szoveg, i, 1));
IF v_Elofordulasok.EXISTS(c) THEN
v_Elofordulasok(c) := v_Elofordulasok(c)+1;
ELSE
v_Elofordulasok(c) := 1;
END IF;
END LOOP;
-- Fordított sorrendhez LAST és PRIOR kellene
c := v_Elofordulasok.FIRST;
WHILE c IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(' ''' || c || ''' - '
|| v_Elofordulasok(c));
c := v_Elofordulasok.NEXT(c);
END LOOP;
END elofordulasok;
/
show errors;
ALTER SESSION SET NLS_COMP='ANSI';
-- Ha az NLS_LANG magyar, akkor az NLS_SORT is magyar rendezést ír most elő
-- Egyébként kell még: ALTER SESSION SET NLS_SORT='Hungarian';
EXEC elofordulasok('Babámé');
/*
'a' - 1
'á' - 1
'b' - 2
'é' - 1
'm' - 1
*/
ALTER SESSION SET NLS_COMP='BINARY';
EXEC elofordulasok('Babámé');
/*
'a' - 1
'b' - 2
'm' - 1
'á' - 1
'é' - 1
*/
EXTEND
Alakja:
EXTEND[(n[,m])]
ahol n és m egész.
Beágyazott tábla vagy dinamikus tömb aktuális méretének növelésére szolgál. A paraméter nélküli EXTEND egyetlen NULL elemet helyez el a kollekció végén. Az EXTEND(n) n darab NULL elemet helyez el a kollekció végére. EXTEND(n,m) esetén pedig az m indexű elem n-szer helyeződik el a kollekció végén. Ha a kollekció típusának deklarációjában szerepel a NOT NULL megszorítás, csak az EXTEND harmadik formája alkalmazható.
Egy dinamikus tömb csak a deklarált maximális méretig terjeszthető ki (n értéke legfeljebb LIMIT – COUNT lehet).
Az EXTEND a kollekció belső méretén operál. A PL/SQL megtartja a törölt elemek helyét, ezeknek új érték adható. Az EXTEND használatánál, ha a kollekció végén törölt elemek vannak, a bővítés mögéjük történik.
Például, ha létrehozunk egy beágyazott táblát 5 elemmel, majd a 2. és 5. elemet töröljük, akkor a bővítés az 5. elem után történik (tehát a 6. elemtől). Ekkor COUNT értéke 3, LAST értéke 4.
Példa
DECLARE
v_Szerzok T_Szerzok := T_Szerzok();
BEGIN
DBMS_OUTPUT.PUT_LINE('1. count: ' || v_Szerzok.COUNT
|| ' Limit: ' || NVL(TO_CHAR(v_Szerzok.LIMIT), 'NULL'));
-- Egy NULL elemmel bővítünk
v_Szerzok.EXTEND;
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Szerzok.COUNT
|| ' v_Szerzok(1): ' || NVL(v_Szerzok(1), 'NULL'));
v_Szerzok(1) := 'Móra Ferenc';
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Szerzok.COUNT
|| ' v_Szerzok(v_Szerzok.COUNT): '
|| NVL(v_Szerzok(v_Szerzok.COUNT), 'NULL'));
-- 3 NULL elemmel bővítünk
v_Szerzok.EXTEND(3);
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Szerzok.COUNT
|| ' v_Szerzok(v_Szerzok.COUNT): '
|| NVL(v_Szerzok(v_Szerzok.COUNT), 'NULL'));
-- 4 elemmel bővítünk, ezek értéke az 1. elem értékét veszi fel.
v_Szerzok.EXTEND(4, 1);
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Szerzok.COUNT
|| ' v_Szerzok(v_Szerzok.COUNT): '
|| NVL(v_Szerzok(v_Szerzok.COUNT), 'NULL'));
-- Megpróbáljuk a dinamikus tömböt túlbővíteni
v_Szerzok.EXTEND(10);
EXCEPTION
WHEN SUBSCRIPT_OUTSIDE_LIMIT THEN
DBMS_OUTPUT.PUT_LINE('Kivétel! ' || SQLERRM);
DBMS_OUTPUT.NEW_LINE;
FOR i IN 1..v_Szerzok.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(LPAD(i,2) || ' '
|| NVL(v_Szerzok(i), 'NULL'));
END LOOP;
END;
/
/*
Eredmény:
1. count: 0 Limit: 10
2. count: 1 v_Szerzok(1): NULL
2. count: 1 v_Szerzok(v_Szerzok.COUNT): Móra Ferenc
2. count: 4 v_Szerzok(v_Szerzok.COUNT): NULL
2. count: 8 v_Szerzok(v_Szerzok.COUNT): Móra Ferenc
Kivétel! ORA-06532: Határon kívüli index
1 Móra Ferenc
2 NULL
3 NULL
4 NULL
5 Móra Ferenc
6 Móra Ferenc
7 Móra Ferenc
8 Móra Ferenc
A PL/SQL eljárás sikeresen befejeződött.
*/
TRIM
Alakja
TRIM[(n)]
ahol n egész.
TRIM eltávolítja a kollekció utolsó elemét, TRIM(n) pedig törli az utolsó n elemet. Ha n>COUNT, akkor a SUBSCRIPT_BEYOND_COUNT kivétel váltódik ki. A TRIM a belső méreten operál és az eltávolított elemek helye nem őrződik meg, ezért egy értékadással nem adható nekik új érték.
1. példa
DECLARE
v_Szerzok T_Szerzok;
BEGIN
v_Szerzok := T_Szerzok('Móricz Zsigmond', 'Móra Ferenc',
'Ottlik Géza', 'Weöres Sándor');
DBMS_OUTPUT.PUT_LINE('1. count: ' || v_Szerzok.COUNT);
-- Törlünk egy elemet
v_Szerzok.TRIM;
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Szerzok.COUNT);
-- Törlünk 2 elemet
v_Szerzok.TRIM(2);
DBMS_OUTPUT.PUT_LINE('3. count: ' || v_Szerzok.COUNT);
BEGIN
-- Megpróbálunk túl sok elemet törölni
v_Szerzok.TRIM(10);
EXCEPTION
WHEN SUBSCRIPT_BEYOND_COUNT THEN
DBMS_OUTPUT.PUT_LINE('Kivétel! ' || SQLERRM);
END;
DBMS_OUTPUT.PUT_LINE('4. count: ' || v_Szerzok.COUNT);
END;
/
/* Eredmény:
1. count: 4
2. count: 3
3. count: 1
Kivétel! ORA-06533: Számlálón kívüli indexérték
4. count: 1
A PL/SQL eljárás sikeresen befejeződött.
*/
2. példa
DECLARE
v_Konyvek T_Konyvek := T_Konyvek();
BEGIN
v_Konyvek.EXTEND(20);
DBMS_OUTPUT.PUT_LINE('1. count: ' || v_Konyvek.COUNT);
-- Törlünk pár elemet
v_Konyvek.TRIM(5);
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Konyvek.COUNT);
END;
/
/* Eredmény:
1. count: 20
2. count: 15
A PL/SQL-eljárás sikeresen befejeződött.
*/
DELETE
Alakja
DELETE[(i[,j])]
ahol i és j egész.
A paraméter nélküli DELETE törli a kollekció összes elemét (üres kollekció jön létre). DELETE(i) törli az i indexű elemet, DELETE(i,j) pedig az i és j indexek közé eső minden elemet. Ha i>j vagy valamelyik NULL, akkor a DELETE nem csinál semmit. Dinamikus tömb esetén csak a paraméter nélküli alak használható.
VARCHAR2 típusú kulccsal rendelkező asszociatív tömbnél ha az NLS_COMP inicializációs paraméter értéke ANSI, akkor a kulcsok rendezési sorrendjét az NLS_SORT inicializációs paraméter határozza meg.
Ha beágyazott táblából paraméteres DELETE metódussal törlünk egy vagy több elemet, az lyukat hozhat létre a beágyazott táblában. Az így törölt elemek által lefoglalt hely továbbra is a memóriában marad (a kollekció belső mérete nem változik), de az elemek értékére történő hivatkozás NO_DATA_FOUND kivételt vált ki. A törölt indexeket a FIRST, LAST, NEXT és PRIOR metódusok figyelmen kívül hagyják, a COUNT értéke a törölt elemek számával csökken. A paraméteres alakkal törölt elemeket újra lehet használni egy értékadás után. Tehát az így törölt elemekre nézve a beágyazott tábla az asszociatív tömbhöz hasonlóan viselkedik.
1. példa
DECLARE
TYPE t_nevek IS TABLE OF VARCHAR2(10);
v_Nevek t_nevek := t_nevek('A1', 'B2', 'C3',
'D4', 'E5', 'F6', 'G7', 'H8', 'I9', 'J10');
i PLS_INTEGER;
BEGIN
DBMS_OUTPUT.PUT_LINE('1. count: ' || v_Nevek.COUNT);
-- Törlünk pár elemet
v_Nevek.DELETE(3);
v_Nevek.DELETE(6, 8);
-- Gond nélkül megy ez is
v_Nevek.DELETE(10, 12);
v_Nevek.DELETE(60);
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Nevek.COUNT);
DBMS_OUTPUT.NEW_LINE;
i := v_Nevek.FIRST;
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(LPAD(i,2) || ' '
|| LPAD(v_Nevek(i), 2));
i := v_Nevek.NEXT(i);
END LOOP;
END;
/
/* Eredmény:
1. count: 10
2. count: 5
1 A1
2 B2
4 D4
5 E5
9 I9
A PL/SQL eljárás sikeresen befejeződött.
*/
2. példa
DECLARE
TYPE t_vektor IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
v_Vektor t_vektor;
BEGIN
FOR i IN -2..2 LOOP
v_Vektor(i*2) := i;
END LOOP;
DBMS_OUTPUT.PUT_LINE('1. count: ' || v_Vektor.COUNT);
-- Hány tényleges elem esik ebbe az intervallumba?
v_Vektor.DELETE(-1, 2);
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Vektor.COUNT);
END;
/
/* Eredmény:
1. count: 5
2. count: 3
A PL/SQL eljárás sikeresen befejeződött.
*/
3. példa
DECLARE
TYPE t_tablazat IS TABLE OF NUMBER INDEX BY VARCHAR2(1);
v_Tablazat t_tablazat;
BEGIN
v_Tablazat('a') := 1;
v_Tablazat('A') := 2;
v_Tablazat('z') := 3;
v_Tablazat('Z') := 4;
DBMS_OUTPUT.PUT_LINE('1. count: ' || v_Tablazat.COUNT);
v_Tablazat.DELETE('a','z');
DBMS_OUTPUT.PUT_LINE('2. count: ' || v_Tablazat.COUNT);
END;
/
/*
Eredmény:
1. count: 4
2. count: 2
A PL/SQL eljárás sikeresen befejeződött.
*/