嵌套数组和关联数组有啥区别?

Posted

技术标签:

【中文标题】嵌套数组和关联数组有啥区别?【英文标题】:What is the difference between nested array and associative array?嵌套数组和关联数组有什么区别? 【发布时间】:2015-01-31 19:55:00 【问题描述】:

有两个链接 http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS99981 和

Purpose of using different types of PL/SQL collections in Oracle

通过参考以上两个链接,我有两个疑问

1.哪一个是正确的嵌套表?

2.如果oracle doc是正确的,嵌套表和关联数组有什么区别?

【问题讨论】:

两者都很好。简而言之,关联数组有一个INDEX BY 子句,而嵌套表没有。 如果在 oracle 文档(您提供的第一个链接)中向上滚动一点,您会看到表 5-1,其中突出显示了不同集合类型之间的差异和相似之处。 另一个重要区别:您可以在数据库级别创建嵌套表,并且可以在表中将它们用作列类型。使用关联数组,您无法做到这一点。 【参考方案1】:

嵌套表只是一个包含 n 个元素的数组。

declare
  type nested_table_of_integer is table of integer;
  v_my_nested_table nested_table_of_integer;
begin
  v_my_nested_table := nested_table_of_integer(); -- initialize
  v_my_nested_table.extend(10); -- add 10 elements
  v_my_nested_table(1) := 100;
  v_my_nested_table(11) := 1000; -- ORA-06533: Subscript beyond count
end;

嵌套表必须如图所示进行初始化。一开始它的元素为零。要添加元素,我们使用 EXTEND。这个嵌套表有 10 个元素。它们的索引为 1 到 10。元素 1 的值为 100。其他元素的值为 null。访问不存在的元素(例如第 11 个元素)会引发错误。

另一方面,关联数组是名称/值对的数组。让我们使用数字(通常为 pls_integer)来命名:

declare
  type associative_array_of_integer is table of integer index by pls_integer;
  v_my_associative_array associative_array_of_integer;
begin
  v_my_associative_array(1) := 100;
  v_my_associative_array(11) := 1000;
  v_my_associative_array(12) := v_my_associative_array(2); -- ORA-01403: no data found
end;

关联数组不需要初始化。它是空的并且被填充。这里我们将名为 1 的元素与值 100 相关联,将名为 11 的元素与值 1000 相关联。所以数组中有两个元素。当我们尝试访问不在数组中的名称时,我们得到一个找不到数据的异常。

我们也可以使用字符串作为名称:

declare
  type associative_array_of_integer is table of integer index by varchar2(100);
  v_my_associative_array associative_array_of_integer;
begin
  v_my_associative_array('age father') := 39;
  v_my_associative_array('age mother') := 32;
  v_my_associative_array('age daughter') := 11;
end;

您可以使用这两个集合来获取表数据,但使用方式不同。嵌套表有一个计数,你可以从 1 循环到计数来访问它的元素:

declare
  type nested_table_of_integer is table of integer;
  v_my_nested_table nested_table_of_integer;
begin
  v_my_nested_table := nested_table_of_integer(); -- initialize
  select table_name bulk collect into v_my_nested_table from user_tables;
  for i in 1 .. v_my_nested_table.count loop
    dbms_output.put_line(v_my_nested_table(i));
  end loop;
end;

然而,关联数组必须使用 FIRST 和 NEXT 从恰好是 next 和 next 和 next 的第一个索引中读取。

declare
  type associative_array_of_integer is table of integer index by pls_integer;
  v_my_associative_array associative_array_of_integer;
  i integer;
 begin
  select table_name bulk collect into v_my_associative_array from user_tables;
  i := v_my_associative_array.first;
  while i is not null loop
    dbms_output.put_line(v_my_associative_array(i));
    i := v_my_associative_array.next(i);
  end loop;
end;

这里的“名称”恰好是 1、2、3 等(因此由批量集合给出),例如,您可以访问 v_my_associative_array(1)。然而,在你的程序后面,在数组中进行一些可能的删除操作之后,可能会出现间隙,所以你不知道是否存在名为 1 的元素,也不知道元素 4 之前的元素是否恰好是元素 3。与批量收集一样元素的“名称”没有任何意义,您不会真正使用它们,而是通过如图所示的链。

【讨论】:

感谢 Thorsten 的精彩描述。我真的很感激。 您可能应该添加最重要的区别:性能!为正确的工作使用正确的工具!关联数组总是像单索引查找一样,而嵌套表像全表扫描一样工作。根据您的需要,其中一个会比另一个快得多! (我讨厌 Oracle 使用这种模棱两可的语法) @Falco:我同意,这种语法让我经常感到困惑。对于给定的任务使用适当的集合也是正确的。但是,我认为您与索引查找和全表扫描的类比有其缺陷。 v_my_nested_table(2) 只是内存中的第二个元素,因此可以直接访问,而必须查找 v_my_associative_array(2)。是这个意思吗? @Falco:你确定吗?当您在内存中使用它们时,差异应该是微不足道的 - 除非您的嵌套表或关联数组包含数百万个条目。对于表中的数据,这种camparison 不适用,因为您不能将关联数组存储在表中。 @Wernfried 我错了...我刚刚运行了一些基准测试,似乎 11g 和 12c 在访问嵌套表和关联数组之间几乎没有区别...使用 12c,您甚至可以使用 SELECT-Queries在关联数组上! - 所以嵌套表的唯一好处似乎是保存在数据库中......【参考方案2】:

这是另一个不为人知的区别。您可以将两个嵌套表与=<> 进行比较,但您不能使用关联数组。

DECLARE

    TYPE associative_array IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
    a_var_associative_array associative_array;
    b_var_associative_array associative_array;

    TYPE nested_table IS TABLE OF INTEGER;
    a_var_nested_table nested_table := nested_table(1, 2, 3, 4, 5);
    b_var_nested_table nested_table := nested_table(5, 4, 3, 2, 1);

BEGIN

    IF a_var_nested_table = b_var_nested_table THEN
        -- Note, the different order of values!
        DBMS_OUTPUT.PUT_LINE ( 'TRUE' );
    ELSE
        DBMS_OUTPUT.PUT_LINE ( 'FALSE' );
    END IF;

    -- IF a_var_associative_array = b_var_associative_array THEN -> gives you an error! 

END;

当您使用嵌套表时,您还可以使用 Multiset Operators、Multiset Conditions 和 SET,它们不适用于关联数组。

【讨论】:

感谢您的回答,但据我所知,如果我们使用关联数组并在其中放入一些值,它存储的顺序不是我们输入的排序顺序,由此我知道嵌套表也排序数据,但是为什么关联数组无法比较,因为它在 PGA 中也分配了一些内存? @Wernfried:感谢您提供的信息。我不知道。因此,嵌套表在比较时被视为多重集。很有趣。 @PuneetKushwah:我不知道甲骨文为什么会有所作为。可能是因为关联数组没有固定大小。 我今天拿到了 OCA 证书,但是没有任何 Oracle 身份证,你能告诉我为什么吗?

以上是关于嵌套数组和关联数组有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

php判断数组是关联数组还是数值数组

如何在powershell中将嵌套的任意关联数组值设置为.psd1文件?

mongoose 怎么插入嵌套数组

PHP关联数组赋值方法的区别

无法从 JDBC 获取 OUT 参数中的二维关联数组

使用嵌套的每个循环构建多维数组?