Oracle PL/SQL – Cum se creează o variabilă de matrice simplă? (Programare, Oracle, Plsql, Oracle9I)

contactmatt a intrebat.

Aș dori să creez o variabilă de matrice în memorie care să poată fi utilizată în codul meu PL/SQL. Nu găsesc în Oracle PL/SQL nicio colecție care să folosească memoria pură, toate par să fie asociate cu tabele. Caut să fac ceva de genul acesta în PL/SQL-ul meu (sintaxa C#):

string[] arrayvalues = new string[3] {"Matt", "Joanne", "Robert"};

Editați:Oracle: 9i

Comentarii

5 răspunsuri
Tony Andrews

Puteți utiliza VARRAY pentru o matrice de dimensiuni fixe:

declare
   type array_t is varray(3) of varchar2(10);
   array array_t := array_t('Matt', 'Joanne', 'Robert');
begin
   for i in 1..array.count loop
       dbms_output.put_line(array(i));
   end loop;
end;

Sau TABLE pentru o matrice nelimitată:

...
   type array_t is table of varchar2(10);
...

Cuvântul „tabel” aici nu are nimic de-a face cu tabelele din baza de date, ceea ce este derutant. Ambele metode creează array-uri în memorie.

Cu oricare dintre acestea trebuie să inițializați și să extindeți colecția înainte de a adăuga elemente:

declare
   type array_t is varray(3) of varchar2(10);
   array array_t := array_t(); -- Initialise it
begin
   for i in 1..3 loop
      array.extend(); -- Extend it
      array(i) := 'x';
   end loop;
end;

Primul indice este 1 și nu 0.

Comentarii

    84

  • „în mod confuz” rezumă în mare parte Oracle –  > Por m.edmondson.
  • Pot să inserez în tabele în același mod ca și în array-uri? adică. my_array(0) := 'some string'; –  > Por Abdul.
  • @TonyAndrews array.extend(); EXTEND adaugă un slot la o matrice delimitată obișnuită? În acest caz, dimensiunea este deja dinamică, astfel încât nu ar mai fi nevoie de un tabel (matrice nemărginită). –  > Por Abdul.
  • @Abdul, nu, nu o face. În mod normal, nu folosesc niciodată VARRAY-uri, dar când am testat codul de mai sus am verificat ce se întâmplă dacă încerci să extinzi un VARRAY varray(3) de 4 ori – primești o eroare „subscript out of limit”. –  > Por Tony Andrews.
  • Mi-aș dori să pot vota acest răspuns de mai multe ori @TonyAndrews, deoarece ați acoperit array.extend(). Peste tot unde m-am uitat nu a arătat acest lucru și a fost cea mai importantă parte pentru a putea adăuga mai mult de un element (din ceea ce am înțeles eu, încă sunt nou la array-uri în SQL). –  > Por Jonathan Van Dam.
Ollie

Ați putea declara un DBMS_SQL.VARCHAR2_TABLE pentru a păstra o matrice de lungime variabilă în memorie indexată cu un BINARY_INTEGER:

DECLARE
   name_array dbms_sql.varchar2_table;
BEGIN
   name_array(1) := 'Tim';
   name_array(2) := 'Daisy';
   name_array(3) := 'Mike';
   name_array(4) := 'Marsha';
   --
   FOR i IN name_array.FIRST .. name_array.LAST
   LOOP
      -- Do something
   END LOOP;
END;

Ați putea utiliza un array asociativ (care se numea tabele PL/SQL), deoarece acestea sunt un array în memorie.

DECLARE
   TYPE employee_arraytype IS TABLE OF employee%ROWTYPE
        INDEX BY PLS_INTEGER;
   employee_array employee_arraytype;
BEGIN
   SELECT *
     BULK COLLECT INTO employee_array
     FROM employee
    WHERE department = 10;
   --
   FOR i IN employee_array.FIRST .. employee_array.LAST
   LOOP
      -- Do something
   END LOOP;
END;

Rețeaua asociativă poate conține orice tip de înregistrare.

Sper să vă fie de ajutor, Ollie.

Comentarii

    17

  • Condiția de iterație ridică VALUE_ERROR atunci când colecția este goală. V-aș sugera să folosiți mai degrabă FOR i IN 1 .. employee_array.COUNT în acest caz –  > Por unziberla.
  • versiunea lui j-chomel (stackoverflow.com/a/40579334/1915920) bazată pe sys.odcivarchar2list de mai jos are avantajul, că aveți la îndemână și un constructor, de exemplu pentru inițializarea implicită a parametrilor de funcție: sys.odcivarchar2list('val1','val2') –  > Por Andreas Covidiot.
Jika

De asemenea, puteți utiliza un oracle defined collection

DECLARE 
  arrayvalues sys.odcivarchar2list;
BEGIN
  arrayvalues := sys.odcivarchar2list('Matt','Joanne','Robert');
  FOR x IN ( SELECT m.column_value m_value
               FROM table(arrayvalues) m )
  LOOP
    dbms_output.put_line (x.m_value||' is a good pal');
  END LOOP;
END;

Eu aș folosi o matrice în memorie. Dar cu .COUNT îmbunătățirea sugerată de uziberia:

DECLARE
  TYPE t_people IS TABLE OF varchar2(10) INDEX BY PLS_INTEGER;
  arrayvalues t_people;
BEGIN
  SELECT *
   BULK COLLECT INTO arrayvalues
   FROM (select 'Matt' m_value from dual union all
         select 'Joanne'       from dual union all
         select 'Robert'       from dual
    )
  ;
  --
  FOR i IN 1 .. arrayvalues.COUNT
  LOOP
    dbms_output.put_line(arrayvalues(i)||' is my friend');
  END LOOP;
END;

O altă soluție ar fi să folosiți un Hashmap așa cum a făcut @Jchomel aici.

NB:

Cu Oracle 12c puteți chiar să interogați array-uri direct acum!

J. Chomel

O altă soluție ar fi să folosiți o colecție Oracle Collection ca Hashmap:

declare 
-- create a type for your "Array" - it can be of any kind, record might be useful
  type hash_map is table of varchar2(1000) index by varchar2(30);
  my_hmap hash_map ;
-- i will be your iterator: it must be of the index's type
  i varchar2(30);
begin
  my_hmap('a') := 'apple';
  my_hmap('b') := 'box';
  my_hmap('c') := 'crow';
-- then how you use it:

  dbms_output.put_line (my_hmap('c')) ;

-- or to loop on every element - it's a "collection"
  i := my_hmap.FIRST;

  while (i is not null)  loop     
    dbms_output.put_line(my_hmap(i));      
    i := my_hmap.NEXT(i);
  end loop;

end;

sudhirkondle

Exemple de programe după cum urmează și furnizate și pe link https://oracle-concepts-learning.blogspot.com/

tabel plsql sau matrice asociată.

        DECLARE 
            TYPE salary IS TABLE OF NUMBER INDEX BY VARCHAR2(20); 
            salary_list salary; 
            name VARCHAR2(20); 
        BEGIN 
           -- adding elements to the table 
           salary_list('Rajnish') := 62000; salary_list('Minakshi') := 75000; 
           salary_list('Martin') := 100000; salary_list('James') := 78000; 
           -- printing the table name := salary_list.FIRST; WHILE name IS NOT null 
            LOOP 
               dbms_output.put_line ('Salary of ' || name || ' is ' || 
               TO_CHAR(salary_list(name))); 
               name := salary_list.NEXT(name); 
            END LOOP; 
        END; 
        /