Oracle PL / SQL-単純な配列変数を作成する方法


128

PL / SQLコードで使用できるインメモリ配列変数を作成したいのですが。純粋なメモリを使用するOracle PL / SQLでコレクションを見つけることができません。それらはすべてテーブルに関連付けられているようです。PL / SQL(C#構文)で次のようなことをしたいと考えています。

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

編集: Oracle:9i



1
「テーブル」参照は、古いPL / SQLテーブルのネーミングからの二日酔いになる傾向があります。VARRAY、連想配列、および宣言されたネストされたテーブルは、すべてメモリ内配列型です。
Ollie

回答:


244

固定サイズの配列にはVARRAYを使用できます。

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;

または無制限配列のTABLE:

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

ここで「テーブル」という言葉は、データベーステーブルとはまったく関係がなく、混乱を招きます。どちらの方法でも、メモリ内配列が作成されます。

これらのいずれかを使用して、要素を追加する前にコレクションを初期化および拡張する必要があります。

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;

最初のインデックスは0ではなく1です。


75
「紛らわしい」とはOracleを要約したものです
m.edmondson 2015年

配列と同じ方法でテーブルに挿入できますか?iemy_array(0) := 'some string';
Abdul

@TonyAndrews array.extend();EXTENDは通常の有界配列にスロットを追加しますか?その場合、サイズは既に動的であるため、テーブル(無制限の配列)は必要ありません。
Abdul

2
@アブドゥル、そうではない。私は通常VARRAYを使用しませんが、上記のコードをテストするときに、varray(3)4回拡張しようとするとどうなるかを確認しました。「添え字が制限を超えています」というエラーが表示されます。
トニーアンドリュース

2
あなたがをカバーしたので、私はこの回答を@TonyAndrewsに何度も投票することを勧めますarray.extend()。私が見たところすべてがこれを示しているわけではなく、複数の項目を追加できることが最も重要な部分でした(私の理解から、SQLの配列にはまだ新しい)。
ジョナサンヴァンダム

61

DBMS_SQL.VARCHAR2_TABLEを宣言して、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;

メモリー内配列であるため、PL / SQL表と呼ばれていた連想配列を使用できます。

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;

連想配列は、あらゆる種類のレコードタイプを保持できます。

それが役に立てば幸い、Ollie。


17
VALUE_ERRORコレクションが空の場合、反復条件が発生します。FOR i IN 1 .. employee_array.COUNTこの場合はむしろ使用することをお勧めします
unziberla

以下に基づくj-chomelのバージョン(stackoverflow.com/a/40579334/1915920)にsys.odcivarchar2listは、コンストラクターも手元にあるという利点があります。たとえば、関数paramのデフォルト初期化の場合:sys.odcivarchar2list('val1','val2')
Andreas Dietrich

11

別の解決策は、Oracleコレクションをハッシュマップとして使用することです。

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

また、 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;

インメモリ配列を使用します。しかし、.COUNTウジベリアによって提案された改善により:

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;

別の解決策は、@ Jchomelのようにハッシュマップを使用することです。 ここでたです。

注意:

Oracle 12cを使用すると、配列を直接クエリすることできます


1

以下のサンプルプログラムとリンクにも提供 https://oracle-concepts-learning.blogspot.com/

plsqlテーブルまたは関連する配列。

        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; 
        /
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.