Oracle PL / SQL - Wie erstelle ich eine einfache Array-Variable?

128

Ich möchte eine speicherinterne Array-Variable erstellen, die in meinem PL / SQL-Code verwendet werden kann. Ich kann in Oracle PL / SQL keine Sammlungen finden, die reinen Speicher verwenden. Alle scheinen mit Tabellen verknüpft zu sein. Ich möchte in meinem PL / SQL (C # -Syntax) so etwas tun:

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

Bearbeiten: Oracle: 9i

Kontaktmatt
quelle
1
Die "Tabellen" -Referenz ist in der Regel ein Kater der alten PL / SQL-Tabellennamen. VARRAYs, assoziative Arrays und deklarierte verschachtelte Tabellen sind speicherinterne Array-Typen.
Ollie

Antworten:

244

Sie können VARRAY für ein Array mit fester Größe verwenden:

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;

Oder TABELLE für ein unbegrenztes Array:

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

Das Wort "Tabelle" hat hier verwirrenderweise nichts mit Datenbanktabellen zu tun. Beide Methoden erstellen In-Memory-Arrays.

In beiden Fällen müssen Sie die Sammlung initialisieren und erweitern, bevor Sie Elemente hinzufügen:

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;

Der erste Index ist 1 nicht 0.

Tony Andrews
quelle
74
"verwirrend" fasst Oracle
m.edmondson
Füge ich wie Arrays in Tabellen ein? dhmy_array(0) := 'some string';
Abdul
@TonyAndrews array.extend();fügt EXTEND einem regulären begrenzten Array einen Slot hinzu? In diesem Fall ist die Größe bereits dynamisch, sodass keine Tabelle (unbegrenztes Array) benötigt wird.
Abdul
2
@Abdul, nein, tut es nicht. Normalerweise verwende ich VARRAYs nie, aber beim Testen des obigen Codes habe ich überprüft, was passiert, wenn Sie versuchen, einen varray(3)4-fachen zu verlängern. Es wird der Fehler "Index außerhalb des Grenzwerts" angezeigt.
Tony Andrews
2
Ich wünschte, ich könnte diese Antwort mehrmals bei TonyAndrews abstimmen, seit Sie die array.extend(). Jeder Ort, an dem ich nachgesehen habe, hat dies nicht gezeigt, und es war der wichtigste Teil, mehr als ein Element hinzufügen zu können (nach meinem Verständnis noch neu für Arrays in SQL).
Jonathan Van Dam
61

Sie können einfach eine DBMS_SQL.VARCHAR2_TABLE deklarieren, die ein speicherinternes Array mit variabler Länge enthält, das von einem BINARY_INTEGER indiziert wird:

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;

Sie können ein assoziatives Array (früher PL / SQL-Tabellen genannt) verwenden, da es sich um ein speicherinternes Array handelt.

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;

Das assoziative Array kann eine beliebige Zusammensetzung von Datensatztypen enthalten.

Hoffe es hilft, Ollie.

Ollie
quelle
17
Die Iterationsbedingung wird ausgelöst, VALUE_ERRORwenn die Sammlung leer ist. Ich würde vorschlagen, FOR i IN 1 .. employee_array.COUNTin diesem Fall lieber zu verwenden
unziberla
Die auf j-chomel basierende Version ( stackoverflow.com/a/40579334/1915920 ), die auf sys.odcivarchar2listunten basiert, hat den Vorteil, dass Sie auch einen Konstruktor zur Hand haben, z. B. für die Standardinitialisierung von Funktionsparametern:sys.odcivarchar2list('val1','val2')
Andreas Dietrich
11

Eine andere Lösung besteht darin, eine Oracle-Sammlung als Hashmap zu verwenden:

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;
J. Chomel
quelle
11

Sie können auch eine verwenden 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;

Ich würde In-Memory-Array verwenden. Aber mit der .COUNTvon Uziberia vorgeschlagenen Verbesserung:

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;

Eine andere Lösung wäre, eine Hashmap zu verwenden, wie es @Jchomel hier getan hat .

NB:

Mit Oracle 12c können Sie jetzt sogar Arrays direkt abfragen !

Jika
quelle
1

Beispielprogramme wie folgt und auf dem Link auch https://oracle-concepts-learning.blogspot.com/ bereitgestellt

plsql-Tabelle oder zugehöriges Array.

        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; 
        /
Sudhirkondle
quelle