Kollekciómetódusok

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.
*/