PL-SQL - 消除对象表中的间隙

时间:2016-06-10 08:05:21

标签: oracle plsql

T_ATTRIBUTEPAGE_ATTRIBUTELIST作为这样的目标表:

CREATE OR REPLACE TYPE "T_ATTRIBUTEPAGE_ATTRIBUTELIST"  IS TABLE OF o_ATTRIBUTEPAGE_ATTRIBUTELIST;

CREATE OR REPLACE TYPE "O_ATTRIBUTEPAGE_ATTRIBUTELIST" IS OBJECT (
    WizAttrEditID           NUMBER,
    InternalIndex           NUMBER,
    DimensionObjectID       NUMBER,
    AttributeName           VARCHAR2(50),
    AttributeLabel          VARCHAR2(50),
    AttributeType           NUMBER,
    AttributeLength         VARCHAR2(50),
    MandatoryAttribute      NUMBER,
    ReadOnly                NUMBER,
    Name                    VARCHAR2(2000),
    Num                     NUMBER,
    IsModified              NUMBER,
    Colour                  NUMBER);
attributelist     t_attributepage_attributelist;

我正在删除表格中的一项:

attributelist.DELETE(ln_attrib_pos_function);

然后,如果我尝试遍历列表,我有

  

未找到数据

 FOR i in 1..attributelist.COUNT LOOP
      ...
      END LOOP;

我也尝试使用FIRSTLAST方法,但结果是一样的。 我想要的是以某种方式再次使表密集,以便删除后的后续迭代可以没有任何错误。我尝试使用EXISTS方法创建新表并消除与初始表的差距,但我得到了

  

超出计数的订阅

我认为这是因为循环跳过了已删除的项目,因此i索引转向 如果删除的项目位于索引11,则从10到12

FOR i in 1..attributelist.COUNT LOOP
  IF attributelist.EXISTS(i) THEN
    ls_attribute_list.EXTEND;
    ls_attribute_list(i) := attributelist(i);
    ELSE
      CONTINUE;
    END IF;
  END LOOP;
  attributelist := ls_attribute_list;

基本上我希望在删除一个或多个项目后,初始attributelist可以进行迭代。

3 个答案:

答案 0 :(得分:2)

这应该有效

FOR i in attributelist.first..attributelist.last LOOP

如果您在中间删除COUNT减少。 <{1}}和FIRST以及LAST就是您所需要的。

编辑:但是为了避免循环删除的条目,您可以按照MT0的建议进行操作并使用EXISTS

NEXT

使用以下例程测试它:

  i := attributelist.first; 
  LOOP
    dbms_output.put_line(attributelist(i).WizAttrEditID);
    exit when i = attributelist.last; 
    i := attributelist.next(i);
  END LOOP;

输出:

set serveroutput on 
declare
  attributelist      t_attributepage_attributelist;
  ls_attribute_list  t_attributepage_attributelist;
  i                  number;
begin
  attributelist := t_attributepage_attributelist();
  ls_attribute_list := t_attributepage_attributelist();
  attributelist.extend;
  attributelist(1) := O_ATTRIBUTEPAGE_ATTRIBUTELIST(1,null,null,null,null,null,null,null,null,null,null,null,null);
  attributelist.extend;
  attributelist(2) := O_ATTRIBUTEPAGE_ATTRIBUTELIST(2,null,null,null,null,null,null,null,null,null,null,null,null);
  attributelist.extend;
  attributelist(3) := O_ATTRIBUTEPAGE_ATTRIBUTELIST(3,null,null,null,null,null,null,null,null,null,null,null,null);
  attributelist.extend;
  attributelist(4) := O_ATTRIBUTEPAGE_ATTRIBUTELIST(4,null,null,null,null,null,null,null,null,null,null,null,null);
  attributelist.delete(1);
  attributelist.delete(3);
  dbms_output.put_line('count='||attributelist.count||' last='||attributelist.last);
  i := attributelist.first; 
  LOOP
    exit when i is null; -- in case everything is deleted
    dbms_output.put_line(attributelist(i).WizAttrEditID);
    exit when i = attributelist.last; 
    i := attributelist.next(i);
  END LOOP;
end;

答案 1 :(得分:1)

最好的解决方案是接受如果您要从集合中删除它们,那么它们可以是稀疏的并使用FIRST/LAST/NEXT方法迭代它们:

i := attributeList.FIRST;
LOOP
  -- do stuff
  EXIT WHEN i = attributeList.LAST;
  i := attributeList.NEXT(i);
END LOOP;

是的,输入比FOR i IN attributeList.FIRST .. attributeList.LAST LOOP ... do stuff ... END LOOP;稍微多一些但不是很多,当您忘记处理几个程序之前的删除时,您的应用程序逻辑不会突然在随机位置开始破坏。

但是,如果要创建稀疏集合的非稀疏副本,则可以执行以下操作:

CREATE FUNCTION compactCollection(
  list IN  T_ATTRIBUTEPAGE_ATTRIBUTELIST,
) RETURN T_ATTRIBUTEPAGE_ATTRIBUTELIST DETERMINISTIC
IS
BEGIN
  IF list IS NULL THEN
    RETURN NULL;
  END IF;

  RETURN T_ATTRIBUTEPAGE_ATTRIBUTELIST()
           MULTISET UNION list;
END;
/

但最好只使用适当的迭代方法进行稀疏集合。

<强>更新

MULTISET UNION运算符将连接两个集合,返回一个新集合(与操作数类型相同)。连接的副作用是产生的集合是密集的。

因此,将空集合与稀疏集合连接将导致稀疏集合的压缩(密集)版本。

attributeList := T_ATTRIBUTEPAGE_ATTRIBUTELIST() MULTISET UNION attributeList;

将给出相同的元素(以相同的顺序),但只是压缩元素索引。

(如果您希望使用FIRST/LAST/NEXT次迭代的较长版本的代码,请参阅first edit of this answer

答案 2 :(得分:0)

我设法做的似乎工作是使用一个辅助的对象表,我用删除的项目迭代原始数组,然后删除一些辅助列表中的间隙,然后将此列表返回给原始数组,如下所示:

FOR i in 1..attributelist.COUNT+1 LOOP
      IF attributelist.EXISTS(i) THEN
        j := j+1;
        ls_attribute_list.EXTEND;
        ls_attribute_list(j) := attributelist(i);
        END IF;
      END LOOP;
      attributelist := ls_attribute_list;