Oracle PL / SQL - Bagaimana cara membuat variabel array sederhana?

128

Saya ingin membuat variabel array dalam memori yang dapat digunakan dalam kode PL / SQL saya. Saya tidak dapat menemukan koleksi di Oracle PL / SQL yang menggunakan memori murni, semuanya tampaknya terkait dengan tabel. Saya ingin melakukan sesuatu seperti ini di PL / SQL (sintaks C #) saya:

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

Sunting: Oracle: 9i

contactmatt
sumber
2
Lihat: Koleksi dan Catatan PL / SQL
user272735
1
Referensi "tabel" cenderung hangover dari penamaan tabel PL / SQL lama. VARRAY, Array Asosiatif, dan tabel bertingkat yang diumumkan adalah semua jenis array dalam memori.
Ollie

Jawaban:

244

Anda dapat menggunakan VARRAY untuk array ukuran tetap:

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;

Atau TABEL untuk larik tak terbatas:

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

Kata "tabel" di sini tidak ada hubungannya dengan tabel database, membingungkan. Kedua metode membuat array dalam memori.

Dengan salah satu dari ini, Anda perlu menginisialisasi dan memperluas koleksi sebelum menambahkan elemen:

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;

Indeks pertama adalah 1 bukan 0.

Tony Andrews
sumber
75
"membingungkan" hanya meringkas Oracle
m.edmondson
Apakah saya memasukkan ke dalam tabel dengan cara yang sama seperti array? yaitumy_array(0) := 'some string';
Abdul
@TonyAndrews array.extend();apakah EXTEND menambahkan slot ke array terikat reguler? Dalam hal ini, ukurannya sudah dinamis sehingga sebuah tabel (array tidak terikat) tidak diperlukan.
Abdul
2
@ Abdul, tidak, tidak. Saya tidak pernah menggunakan VARRAYs secara normal tetapi ketika menguji kode di atas saya memeriksa apa yang terjadi jika Anda mencoba untuk memperpanjang varray(3)4 kali - Anda mendapatkan kesalahan "subskrip di luar batas".
Tony Andrews
2
Seandainya saya dapat memilih jawaban ini beberapa kali @TonyAndrews sejak Anda meliput array.extend(). Setiap tempat saya melihat tidak menunjukkan ini dan itu adalah bagian paling penting untuk dapat menambahkan lebih dari satu item (dari pemahaman saya tentang hal itu, masih baru untuk array dalam SQL).
Jonathan Van Dam
61

Anda bisa mendeklarasikan DBMS_SQL.VARCHAR2_TABLE untuk menahan array panjang variabel di dalam memori yang diindeks oleh 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;

Anda bisa menggunakan array asosiatif (dulu disebut tabel PL / SQL) karena array dalam memori.

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;

Array asosiatif dapat menampung jenis rekaman apa pun.

Semoga ini bisa membantu, Ollie.

Ollie
sumber
17
Kondisi iterasi meningkat VALUE_ERRORketika koleksi kosong. Saya akan menyarankan untuk menggunakan FOR i IN 1 .. employee_array.COUNTdalam kasus ini
unziberla
Versi j-chomel ( stackoverflow.com/a/40579334/1915920 ) berdasarkan di sys.odcivarchar2listbawah ini memiliki keuntungan, bahwa Anda juga memiliki konstruktor, misalnya untuk inisialisasi fungsi param standar:sys.odcivarchar2list('val1','val2')
Andreas Dietrich
11

Solusi lain adalah dengan menggunakan Oracle Collection sebagai 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;
J. Chomel
sumber
11

Anda juga dapat menggunakan 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;

Saya akan menggunakan array dalam memori. Tetapi dengan .COUNTperbaikan yang disarankan oleh 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;

Solusi lain adalah dengan menggunakan Hashmap seperti @Jchomel lakukan di sini .

NB:

Dengan Oracle 12c Anda bahkan dapat meminta array langsung sekarang !

Jika
sumber
1

Contoh program sebagai berikut dan disediakan di tautan juga https://oracle-concepts-learning.blogspot.com/

tabel plsql atau larik terkait.

        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
sumber