我可以告诉PLSQL集合删除修剪过的PLSQL集合中的最后一个元素吗?

时间:2016-09-15 20:51:40

标签: oracle collections plsql

只是理论问题:

嵌套表由于删除而变得稀疏,这可以通过在first之间的nextlast之间的索引序列中创建漏洞来证明。 但是,如果删除last索引,则集合边界与修剪last索引完全相同(或者就像集合从未扩展到该索引一样)。 有没有办法区分这种差异?

declare
  type ct is table of varchar2(200);
  a ct := ct('x','y','z');
  b ct := ct('x','y','z');
begin
  a.delete(3);
  b.trim();
  -- first=1, last=2, count=2 here for both a and b
  a(3) := 'l'; -- legal since delete keeps room for 3rd element extended
  --b(3) := 'l'; -- illegal since trim is inversion of extend
end;

换句话说,如果Alice删除并修剪Bob,我可以告诉谁创建了哪个集合(除了尝试在索引last+1插入并捕获潜在的ORA-06533 Subscript beyond count错误)?谢谢!

1 个答案:

答案 0 :(得分:1)

这里的区别在于delete后嵌套表变为稀疏但在trim之后它仍然是密集。 PL / SQL没有提供(简单)工具来检查嵌套表是稀疏还是密集的 - 如果他正在使用稀疏或密集的嵌套表,那么程序员有责任一直知道。

a.delete(3)b.trim之后的特定示例中,PL / SQL为您提供了无法以编程方式检查a(3) := 'x'b(3) := 'x'是否有效的工具。除非,正如您所指出的那样,尝试并捕获潜在的异常。通常,您必须跟踪嵌套的表大小。

我的经验法则是,始终保持其嵌套表密集,并使用关联数组进行稀疏集合。如果只需要嵌套表元素的子集,则为子集创建一个新的密集嵌套表。

示例

declare
  type str_list_t is table of varchar2(1);

  a str_list_t := str_list_t('a', 'b', 'c'); -- dense
  b str_list_t := str_list_t('a', 'b', 'c'); -- dense

  procedure d(p_strs in str_list_t) is
    s varchar2(32767);
  begin
    s := '(count ' || p_strs.count || ')';
    s := s || '(first ' || p_strs.first || ')';
    s := s || '(last ' || p_strs.last || ')';

    s := s || '(';
    for i in p_strs.first .. p_strs.last
    loop
      s := s || '(' || i || ' ' || p_strs(i) || ')';
    end loop;
    s := s || ')';

    dbms_output.put_line(s);
  end;
begin
  a.delete(3); d(a); -- collection becomes sparse
  b.trim;      d(b); -- remains dense

  -- exists won't help you as a(3) doesn't exists and exists returns false
  if a.exists(3) then a(3) := 'C'; end if;
  if b.exists(3) then b(3) := 'C'; end if;

  d(a);
  d(b);

  a(3) := 'D'; d(a); -- ok
  b(3) := 'D'; d(b); -- ORA-06533: Subscript beyond count
end;
/

<强>结果

(count 2)(first 1)(last 2)((1 a)(2 b))
(count 2)(first 1)(last 2)((1 a)(2 b))
(count 2)(first 1)(last 2)((1 a)(2 b))
(count 2)(first 1)(last 2)((1 a)(2 b))
(count 3)(first 1)(last 3)((1 a)(2 b)(3 D))
declare
*
ERROR at line 1:
ORA-06533: Subscript beyond count
ORA-06512: at line 35