Oracle PL / SQL - Basit bir dizi değişkeni nasıl oluşturulur?


128

PL / SQL kodumda kullanılabilecek bir bellek içi dizi değişkeni oluşturmak istiyorum. Oracle PL / SQL'de saf bellek kullanan herhangi bir koleksiyon bulamıyorum, hepsi tablolarla ilişkili görünüyor. PL / SQL (C # sözdizimimde) buna benzer bir şey yapmak istiyorum:

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

Düzenleme: Oracle: 9i



1
"Tablo" referansı, eski PL / SQL tablolarının adlandırılmasından kaynaklanan bir akşamdan kalma olma eğilimindedir. VARRAY'ler, İlişkili Diziler ve Bildirilen iç içe geçmiş tabloların tümü bellek içi dizi türleridir.
Ollie

Yanıtlar:


244

Sabit boyutlu bir dizi için VARRAY'i kullanabilirsiniz:

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;

Veya sınırsız bir dizi için TABLO:

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

Buradaki "tablo" kelimesinin veritabanı tablolarıyla hiçbir ilgisi yoktur, kafa karıştırıcıdır. Her iki yöntem de bellek içi diziler oluşturur.

Bunlardan herhangi biriyle, öğe eklemeden önce koleksiyonu hem başlatmanız hem de genişletmeniz gerekir:

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;

İlk indeks 0 değil 1'dir.


75
"kafa karıştırıcı" Oracle'ı özetliyor
m.edmondson

Tablolara dizilerle aynı şekilde ekler miyim? yanimy_array(0) := 'some string';
Abdul

@TonyAndrews array.extend();EXTEND, normal sınırlı diziye bir yuva ekler mi? Bu durumda, boyut olarak zaten dinamik olduğundan bir tabloya (sınırsız dizi) gerek kalmayacaktır.
Abdul

2
@Abdul, hayır öyle değil. VARRAY'leri asla normal olarak kullanmam ama yukarıdaki kodu test ederken varray(3)4 kez uzatmaya çalışırsanız ne olacağını kontrol ettim - "alt simge limit dışı" hatası alıyorsunuz.
Tony Andrews

2
Keşke bu yanıtı defalarca oylayabilsem @TonyAndrews array.extend(). Baktığım her yerde bunu göstermiyordu ve birden fazla öğe ekleyebilmenin en önemli parçasıydı (benim anladığım kadarıyla, SQL'deki diziler için hala yeni).
Jonathan Van Dam

61

Bir BINARY_INTEGER tarafından indekslenmiş bir bellek içi değişken uzunluk dizisini tutmak için bir DBMS_SQL.VARCHAR2_TABLE tanımlayabilirsiniz:

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;

Bellek içi bir dizi oldukları için ilişkilendirilebilir bir dizi (PL / SQL tabloları olarak adlandırılırdı) kullanabilirsiniz.

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;

İlişkilendirilebilir dizi, herhangi bir kayıt tipini tutabilir.

Umarım yardımcı olur, Ollie.


17
VALUE_ERRORKoleksiyon boş olduğunda yineleme koşulu yükselir . FOR i IN 1 .. employee_array.COUNTBu durumda kullanmayı tercih ederim
unziberla

j-chomel'in aşağıya dayalı sürümü ( stackoverflow.com/a/40579334/1915920 ) sys.odcivarchar2list, elinizin altında bir kurucu bulundurma avantajına sahiptir, örneğin işlev parametresi varsayılan başlatma için:sys.odcivarchar2list('val1','val2')
Andreas Dietrich

11

Diğer bir çözüm de Oracle Collection'ı Hashmap olarak kullanmaktır:

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;

11

Ayrıca bir 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;

Bellek içi dizi kullanırdım. Ancak .COUNTUziberia'nın önerdiği iyileştirmeyle:

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;

Başka bir çözüm, @Jchomel'in burada yaptığı gibi bir Hashmap kullanmak olabilir .

NB:

Oracle 12c ile dizileri doğrudan şimdi sorgulayabilirsiniz !


1

Aşağıdaki gibi örnek programlar ve bağlantıda ayrıca https://oracle-concepts-learning.blogspot.com/

plsql tablosu veya ilişkili dizi.

        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; 
        /
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.