41.9. 集合

41.9.1. 关联数组
41.9.2. 嵌套表
41.9.3. 可变数组
41.9.4. 集合方法

在集合中,内部组件始终具有相同的数据类型,并称为元素。您可以通过索引访问集合变量的每个元素,语法为:variable_name(index)。 要创建集合变量,您可以定义集合类型,然后创建该类型的变量,或者使用%TYPE

在PL/oraSQL块中定义的集合类型是本地类型。它仅在块中可用,并且仅在块位于独立的或包子程序中时存储在数据库中。

在模式级别定义的集合类型是独立类型。您可以使用“CREATE TYPE语句”创建它。它存储在数据库中,直到您使用“DROP TYPE语句”将其删除。

在包规范中定义的集合类型是公共项。您可以通过使用包名称(package_name.type_name)来限定它从包外引用。它存储在数据库中,直到您删除包。

41.9.1. 关联数组

关联数组是一组键值对。每个键是唯一的索引,用于使用语法variable_name(index)定位关联值。

索引的数据类型可以是字符串类型(VARCHAR 或 VARCHAR2)或INTEGER。索引按排序顺序存储,而不是创建顺序。

导出联合数组操作,当索引的数据类型是varchar2时,会被替换为varchar类型。导入联合数组操作,当索引的数据类型是varchar2时,会被替换为varchar类型。

PERFORM不支持用于操作联合数组并且dbms_output.put_line不支持用于打印关联数组的元素。

例如,定义了一个按integer索引的关联数组类型,声明了该类型的变量,将变量填充到三个元素,更改了一个元素的值,并打印了这些值(按排序顺序,而不是创建顺序)。

DECLARE
  -- Associative array indexed by integer:
  TYPE population IS TABLE OF varchar  -- Associative array type
    INDEX BY integer;                  -- indexed by integer

  city_population  population;        -- Associative array variable
  i                integer;
BEGIN
  -- Add elements (key-value pairs) to associative array:
  city_population('2')  := 'Smallville';
  city_population('5') := 'Midland';
  city_population('3')  := 'Megalopolis';

  FOR i IN 1..6 LOOP
      IF city_population.EXISTS(i) THEN
          dbms_output.put_line ('city_population(' || i || ')' || ' exists');
      ELSE
          dbms_output.put_line ('city_population(' || i || ')' || ' does not exist');
      END IF;
  END LOOP;

END;
/

例如,定义了一个按字符串索引的关联数组类型,声明了该类型的变量,将变量填充到三个元素,更改了一个元素的值,并打印了这些值。

DECLARE
  -- Associative array indexed by varchar2(64):
  
  TYPE population IS TABLE OF NUMERIC  -- Associative array type
    INDEX BY VARCHAR2(64);            --  indexed by varchar2(64)
  
  city_population  population;        -- Associative array variable

BEGIN
  -- Add elements (key-value pairs) to associative array:
  city_population('Smallville')  := 2000;
  city_population('Midland')     := 750000;
  city_population('Megalopolis') := 1000000;

  raise info 'the count elements is %', city_population;

  city_population('Midland')     := 50000;

  raise info 'the count elements is %', city_population;

END;
/

    dbms_output.put_line不支持用于打印关联数组的元素,所以这里使用raise打印元素。

41.9.2. 嵌套表

在数据库中,嵌套表是一种列类型,它以没有特定顺序的方式存储未指定数量的行。

当您将数据库中的嵌套表值检索到PL/oraSQL嵌套表变量中时,PL/oraSQL会为行分配连续的索引,从1开始。使用这些索引,您可以访问嵌套表变量的各个行。 语法是variable_name(index)。随着您将嵌套表从数据库中存储和检索,嵌套表的索引和行顺序可能不会保持稳定。

随着您添加或删除元素,嵌套表变量占用的内存量可以动态增加或减少。

示例:本地类型的嵌套表

DECLARE
TYPE Roster IS TABLE OF VARCHAR(15);  -- nested table type

-- nested table variable initialized with constructor: 
names2 Roster := Roster('D Caruso', 'J Hamil', 'D Piro', 'R Singh');

BEGIN
    DBMS_OUTPUT.PUT_LINE('Initial Values:');
    FOR i IN names2.FIRST .. names2.LAST LOOP  -- For first to last element
      DBMS_OUTPUT.PUT_LINE(names2(i));
    END LOOP;

    DBMS_OUTPUT.PUT_LINE('------------------');
    names2(5) := 'P Perez';  -- add one element
    FOR i IN names2.FIRST .. names2.LAST LOOP  -- For first to last element
      DBMS_OUTPUT.PUT_LINE(names2(i));
    END LOOP;
END;
/

示例:独立类型的嵌套表

CREATE TYPE names2 IS TABLE OF VARCHAR(15);

DECLARE
  nt names2 ;
BEGIN
  nt(1) = 'D Caruso';
  nt(2) = 'J Hamil';
  nt(3) = 'R Singh';
  DBMS_OUTPUT.PUT_LINE(nt(2));
END;
/

示例:复杂类型的嵌套表

create table t(a int,b text);
insert into t values(1,'1');
insert into t values(2,'2');
select dbms_output.serveroutput('t');

create or replace procedure p1 is 
  TYPE array_table IS TABLE OF t%rowtype;
  a_table array_table := array_table();
BEGIN

  SELECT t.* BULK COLLECT INTO a_table FROM t;
  
  FOR i IN a_table.first..a_table.last LOOP
    a_table(i).a := 123;
    a_table(i).b := 'test';
    dbms_output.put_line('a_table(i).a = '||a_table(i).a||', a_table(i).b = '||a_table(i).b);
  END LOOP;
END;
/

示例: 使用嵌套表元素作为插入操作数据源

create table t(a int,b float,c number);
insert into t values(1,10,100);
insert into t values(2,20,200);

create or replace procedure p1 is 
  TYPE array_table IS TABLE OF t%rowtype;
  a_table array_table := array_table();
BEGIN
  SELECT t.* BULK COLLECT INTO a_table FROM t;
  execute immediate 'truncate table t';

  FOR i IN a_table.first..a_table.last LOOP
    a_table(i).a := a_table(i).a * 100;
    a_table(i).b := a_table(i).b * 100;
    a_table(i).c := a_table(i).c * 100;
    INSERT INTO t VALUES a_table(i);
  END LOOP;
END;
/

41.9.3. 可变数组

可变大小数组是一个数组,其元素数量可以从零(空)到声明的最大大小不等,在这里超过也支持。

要访问可变数组的元素,使用语法variable_name(index)。在数据库中存储和检索可变数组时,其索引和元素顺序将保持稳定。

随着您添加或删除元素,可变数组变量占用的内存量可以动态增加或减少。

目前只支持本地类型的可变数组,不支持全局可变数组。

示例:本地类型的可变数组

DECLARE
    TYPE Roster IS VARRAY(10) OF VARCHAR(15);  -- varray type

    -- varray variable initialized with constructor:
    names2 Roster := Roster('D Caruso', 'J Hamil', 'D Piro', 'R Singh');

BEGIN
    DBMS_OUTPUT.PUT_LINE('Initial Values:');
    FOR i IN names2.FIRST .. names2.LAST LOOP  -- For first to last element
        DBMS_OUTPUT.PUT_LINE(names2(i));
    END LOOP;

    DBMS_OUTPUT.PUT_LINE('------------------');
    names2.extend;
    names2(5) := 'P Perez';  -- add one element
    FOR i IN names2.FIRST .. names2.LAST LOOP  -- For first to last element
        DBMS_OUTPUT.PUT_LINE(names2(i));
    END LOOP;
END;
/

41.9.4. 集合方法

集合方法是一个PL/oraSQL子程序,可以是返回有关集合信息的函数,也可以是操作集合的过程。集合方法使集合易于使用,使您的应用程序易于维护。

Table 41.1显示了集合方法。

Table 41.1. 集合方法

方法描述
DELETE从集合中删除元素。
EXTEND将元素添加到嵌套表的末尾。
EXISTS如果嵌套表的指定元素存在,则返回TRUE。
FIRST返回集合中的第一个索引。
LAST返回集合中的最后一个索引。
COUNT返回集合中的元素数量。

集合方法调用的基本语法如下:

collection_name.method