Oracle PL / SQL-如何创建一个简单的数组变量?


128

我想创建一个内存数组变量,该变量可以在我的PL / SQL代码中使用。我在Oracle PL / SQL中找不到使用纯内存的任何集合,它们似乎都与表相关联。我正在PL / SQL(C#语法)中执行以下操作:

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

编辑: 甲骨文:9i



1
“表”引用往往是旧的PL / SQL表命名的一个宿醉。VARRAY,关联数组和声明的嵌套表都是内存中的数组类型。
Ollie

Answers:


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;

第一个索引是1而不是0。


74
“令人困惑”只是总结了甲骨文
m.edmondson

是否以与数组相同的方式插入表中?即my_array(0) := 'some string';
Abdul

@TonyAndrews array.extend();EXTEND是否将插槽添加到常规有界数组?在那种情况下,它的大小已经是动态的,因此不需要表(无界数组)。
阿卜杜勒

2
@Abdul,不,不是。我通常不会使用VARRAY,但是在测试上述代码时,我检查了如果您尝试扩展VARRAY会发生什么情况varray(3) 4次 -您会收到“下标超出限制”错误。
Tony Andrews

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 2014年

基于以下内容的j-chomel版本(stackoverflow.com/a/40579334/1915920sys.odcivarchar2list具有一个优点,即您还有一个构造函数,例如,用于函数param默认初始化:sys.odcivarchar2list('val1','val2')
Andreas Dietrich

11

另一个解决方案是将Oracle集合用作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;

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;

我会使用内存数组。但是随着.COUNTuziberia建议的改进:

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在这里做的Hashmap 。

注意:

使用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; 
        /
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.