Oracle PL-SQL从对象表中删除项

Oracle PL-SQL从对象表中删除项,oracle,plsql,Oracle,Plsql,我正在尝试从对象表类型的变量中删除一项: 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

我正在尝试从对象表类型的变量中删除一项:

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);
我正在查看对象列表,我选中了,ls_attr_list.COUNT为16,我尝试在满足条件时删除一项,但出现以下错误:

ORA-01403:未找到任何数据

在这一行引发:ls_attr_list.Deletei

ls_attr_列表将使用输入参数初始化:

PROCEDURE AttribInit(geninfo        IN OUT    o_geninfo,
                     pageinfo       IN OUT    o_attributepage_pageinfo,
                     attributelist  IN OUT    t_attributepage_attributelist,
                     enumlist       IN OUT    t_attributepage_enumlist)

AS
ls_attr_list := attributelist;
删除一个项目后对列表进行分级时出现问题

i := attributelist.FIRST; 
LOOP 
IF attributelist(i).attributename = 'PROTECTION_ROLE' THEN attributelist.DELETE(i); 
END IF; 
EXIT WHEN i = attributelist.LAST; 
i := attributelist.NEXT(i);
 END LOOP; 
--second FOR
FOR i in 1..attributelist.COUNT LOOP 
-到达上一个已删除项目的索引时未找到数据

我做错了什么,有什么想法吗

FOR i IN 1 .. ls_attr_list.COUNT LOOP
从集合中删除元素时将导致异常/错误。每次删除元素时,它都会在集合中创建一个间隙,下次尝试运行该过程时,它将到达该间隙并抛出一个ORA-01403:找不到数据

相反,您需要在i:=ls\u attr\u list.FIRST和ls\u attr\u list.LAST之间循环,并使用i:=ls\u attr\u list.NEXTi获取下一个索引

一个简化的工作示例是:

CREATE TYPE VARCHAR2_TABLE AS TABLE OF VARCHAR2(20);
/

DECLARE
  vals VARCHAR2_Table := VARCHAR2_Table( 'a', 'b', 'c', 'd', 'e', 'f' );
  PROCEDURE del_Val (
    v IN OUT VARCHAR2_Table,
    x IN     VARCHAR2
  )
  AS
    i INT;
  BEGIN
    IF v IS NULL OR v IS EMPTY THEN
      RETURN;
    END IF;
    i := v.FIRST;
    LOOP
      IF v(i) = x THEN
        DBMS_OUTPUT.PUT_LINE(i);
        v.DELETE(i);
      END IF;
      EXIT WHEN i = v.LAST;
      i := v.NEXT(i);
    END LOOP;
  END;
BEGIN
  del_Val( vals, 'b' );
  del_Val( vals, 'e' );
  del_Val( vals, 'a' );
END;
/
但是,使用此程序:

  PROCEDURE del_Val (
    v IN OUT VARCHAR2_Table,
    x IN     VARCHAR2
  )
  AS
  BEGIN
    FOR i IN 1 .. v.COUNT LOOP
      IF v(i) = x THEN
        DBMS_OUTPUT.PUT_LINE(i);
        v.DELETE(i);
      END IF;
    END LOOP;
  END;
将导致ORA-01403:在第二次调用过程时未找到数据

从集合中删除元素时将导致异常/错误。每次删除元素时,它都会在集合中创建一个间隙,下次尝试运行该过程时,它将到达该间隙并抛出一个ORA-01403:找不到数据

相反,您需要在i:=ls\u attr\u list.FIRST和ls\u attr\u list.LAST之间循环,并使用i:=ls\u attr\u list.NEXTi获取下一个索引

一个简化的工作示例是:

CREATE TYPE VARCHAR2_TABLE AS TABLE OF VARCHAR2(20);
/

DECLARE
  vals VARCHAR2_Table := VARCHAR2_Table( 'a', 'b', 'c', 'd', 'e', 'f' );
  PROCEDURE del_Val (
    v IN OUT VARCHAR2_Table,
    x IN     VARCHAR2
  )
  AS
    i INT;
  BEGIN
    IF v IS NULL OR v IS EMPTY THEN
      RETURN;
    END IF;
    i := v.FIRST;
    LOOP
      IF v(i) = x THEN
        DBMS_OUTPUT.PUT_LINE(i);
        v.DELETE(i);
      END IF;
      EXIT WHEN i = v.LAST;
      i := v.NEXT(i);
    END LOOP;
  END;
BEGIN
  del_Val( vals, 'b' );
  del_Val( vals, 'e' );
  del_Val( vals, 'a' );
END;
/
但是,使用此程序:

  PROCEDURE del_Val (
    v IN OUT VARCHAR2_Table,
    x IN     VARCHAR2
  )
  AS
  BEGIN
    FOR i IN 1 .. v.COUNT LOOP
      IF v(i) = x THEN
        DBMS_OUTPUT.PUT_LINE(i);
        v.DELETE(i);
      END IF;
    END LOOP;
  END;

可能会导致ORA-01403:第二次调用该过程时未找到任何数据。

我已尝试以非常清晰的方式复制该场景,希望这有所帮助

--Obj Creation
CREATE OR REPLACE type av_obj_test
IS
  object
  (
    col1 VARCHAR2(100),
    col2 VARCHAR2(100) );

--TABLE Type creation
CREATE OR REPLACE type av_ntt_test
IS
  TABLE OF av_obj_test;

--Anonymous block  
DECLARE
av_t av_ntt_test:=av_ntt_test(av_obj_test('av','roy'),av_obj_test('sh','roy'));
BEGIN
FOR I IN av_t.FIRST..av_t.LAST LOOP
IF av_t(i).col1 = 'av' THEN
av_t.DELETE(I);
END IF;
END LOOP;
END;

我试图以一种非常清晰的方式复制这个场景,希望这能有所帮助

--Obj Creation
CREATE OR REPLACE type av_obj_test
IS
  object
  (
    col1 VARCHAR2(100),
    col2 VARCHAR2(100) );

--TABLE Type creation
CREATE OR REPLACE type av_ntt_test
IS
  TABLE OF av_obj_test;

--Anonymous block  
DECLARE
av_t av_ntt_test:=av_ntt_test(av_obj_test('av','roy'),av_obj_test('sh','roy'));
BEGIN
FOR I IN av_t.FIRST..av_t.LAST LOOP
IF av_t(i).col1 = 'av' THEN
av_t.DELETE(I);
END IF;
END LOOP;
END;

你没有做错什么。当您删除某个内容时,会有一个间隙导致此错误,如@MT0。 我会稍微使用一下您的代码,然后:

  declare
  t_tab T_ATTRIBUTEPAGE_ATTRIBUTELIST;
  i number;
  begin
t_tab:= T_ATTRIBUTEPAGE_ATTRIBUTELIST ();
t_tab.EXTEND(9);
t_tab(1):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('asd',1);
t_tab(2):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('tyh',2);
t_tab(3):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('adgdfsd',3);
t_tab(4):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('fg',4);
t_tab(5):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('test',5);
t_tab(6):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('test',6);
t_tab(7):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('adaaaasd',7);
t_tab(8):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('qwwwww',8);
t_tab(9):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('poikj',9);
i:=t_tab.FIRST;
LOOP
 dbms_output.put_line(t_tab(i).AttributeName||' '||t_tab(i).AttrNUMBER);

 if t_tab(i).AttributeName = 'test' then t_tab.delete(i);
 t_tab(i):=null;
 end if;


 EXIT when i=t_tab.LAST;
 i:=t_tab.NEXT(i);
 end loop;

 dbms_output.put_line('==============================================');
  for i IN t_tab.FIRST..t_tab.LAST LOOP

  if  t_tab(i) is null then
 continue;
  else
 dbms_output.put_line(t_tab(i).AttributeName||' '||t_tab(i).AttrNUMBER);
  end if;
 end loop;
  end;
    /   
输出:

asd 1
tyh 2
adgdfsd 3
fg 4
test 5
test 6
adaaaasd 7
qwwwww 8
poikj 9
==============================================
asd 1
tyh 2
adgdfsd 3
fg 4
adaaaasd 7
qwwwww 8
poikj 9

在t_tab.deletei之后,a给出t_tabi:=null;这消除了间隙,并且编译器在再次迭代此集合并打印所有项时没有任何问题,因为没有间隙,存在一些东西-NULL,NULL是一些东西,希望您理解:。和adivced上面的用户一样,您应该使用FIRST..LAST而不是count。

您没有做错任何事情。当您删除某个内容时,会有一个间隙导致此错误,如@MT0。 我会稍微使用一下您的代码,然后:

  declare
  t_tab T_ATTRIBUTEPAGE_ATTRIBUTELIST;
  i number;
  begin
t_tab:= T_ATTRIBUTEPAGE_ATTRIBUTELIST ();
t_tab.EXTEND(9);
t_tab(1):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('asd',1);
t_tab(2):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('tyh',2);
t_tab(3):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('adgdfsd',3);
t_tab(4):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('fg',4);
t_tab(5):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('test',5);
t_tab(6):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('test',6);
t_tab(7):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('adaaaasd',7);
t_tab(8):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('qwwwww',8);
t_tab(9):=O_ATTRIBUTEPAGE_ATTRIBUTELIST('poikj',9);
i:=t_tab.FIRST;
LOOP
 dbms_output.put_line(t_tab(i).AttributeName||' '||t_tab(i).AttrNUMBER);

 if t_tab(i).AttributeName = 'test' then t_tab.delete(i);
 t_tab(i):=null;
 end if;


 EXIT when i=t_tab.LAST;
 i:=t_tab.NEXT(i);
 end loop;

 dbms_output.put_line('==============================================');
  for i IN t_tab.FIRST..t_tab.LAST LOOP

  if  t_tab(i) is null then
 continue;
  else
 dbms_output.put_line(t_tab(i).AttributeName||' '||t_tab(i).AttrNUMBER);
  end if;
 end loop;
  end;
    /   
输出:

asd 1
tyh 2
adgdfsd 3
fg 4
test 5
test 6
adaaaasd 7
qwwwww 8
poikj 9
==============================================
asd 1
tyh 2
adgdfsd 3
fg 4
adaaaasd 7
qwwwww 8
poikj 9

在t_tab.deletei之后,a给出t_tabi:=null;这消除了间隙,并且编译器在再次迭代此集合并打印所有项时没有任何问题,因为没有间隙,存在一些东西-NULL,NULL是一些东西,希望您理解:。与adivced上面的用户一样,您应该使用FIRST..LAST而不是count。

即使删除了集合的最后一个元素,下面的内容也可以处理

DECLARE
  TYPE VARCHAR2_TABLE IS TABLE OF VARCHAR2(20);
  vals VARCHAR2_Table := VARCHAR2_Table( 'a', 'b', 'c', 'd', 'e', 'f' );
  PROCEDURE del_Val (
    v IN OUT VARCHAR2_Table,
    x IN     VARCHAR2
  )
  AS
    i INT;
    v_last_deleted boolean;
  BEGIN
    IF v IS NULL OR v IS EMPTY THEN
      DBMS_OUTPUT.PUT_LINE('No more data');
      RETURN;
    END IF;
    i := v.FIRST;
    LOOP
      IF v(i) = x THEN
        DBMS_OUTPUT.PUT_LINE('  -> Delting element at : '||i||' that has vaulue of :'||v(i));
        if (i = v.LAST) then v_last_deleted := true; end if;
        v.DELETE(i);
      ELSE 
        DBMS_OUTPUT.PUT_LINE('  --> Not Delting element at : '||i||' that has vaulue of :'||v(i));      
      END IF;
      EXIT WHEN v IS NULL OR v IS EMPTY OR v_last_deleted OR (i = v.LAST);
      i := v.NEXT(i);
    END LOOP;
  END;
BEGIN
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'b' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'e' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'a' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'a' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'f' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'c' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'a' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'b' );
END;
/

即使删除了集合的最后一个元素,也将处理以下内容

DECLARE
  TYPE VARCHAR2_TABLE IS TABLE OF VARCHAR2(20);
  vals VARCHAR2_Table := VARCHAR2_Table( 'a', 'b', 'c', 'd', 'e', 'f' );
  PROCEDURE del_Val (
    v IN OUT VARCHAR2_Table,
    x IN     VARCHAR2
  )
  AS
    i INT;
    v_last_deleted boolean;
  BEGIN
    IF v IS NULL OR v IS EMPTY THEN
      DBMS_OUTPUT.PUT_LINE('No more data');
      RETURN;
    END IF;
    i := v.FIRST;
    LOOP
      IF v(i) = x THEN
        DBMS_OUTPUT.PUT_LINE('  -> Delting element at : '||i||' that has vaulue of :'||v(i));
        if (i = v.LAST) then v_last_deleted := true; end if;
        v.DELETE(i);
      ELSE 
        DBMS_OUTPUT.PUT_LINE('  --> Not Delting element at : '||i||' that has vaulue of :'||v(i));      
      END IF;
      EXIT WHEN v IS NULL OR v IS EMPTY OR v_last_deleted OR (i = v.LAST);
      i := v.NEXT(i);
    END LOOP;
  END;
BEGIN
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'b' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'e' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'a' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'a' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'f' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'c' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'd' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'a' );
  DBMS_OUTPUT.PUT_LINE('Total Count : '||vals.count);
  del_Val( vals, 'b' );
END;
/

当您从集合中间删除值时,可能需要使用FIRST/LAST/NEXT,而不是使用FOR循环,因为COUNT但是我不能消除这个差距,这样我就可以进一步遍历这个列表了吗?我使用了I:=t_tab.FIRST;环当i=t_tab.LAST时退出;i:=t_tab.NEXTi;端环;要删除该项,eror将在第二次迭代时保持最显式的答案,标记为解决方案,谢谢如果我使用第一个解决方案删除该项,然后在列表中进行迭代,则会引发相同的“未找到数据”异常…@AndreiMaieras这是因为您无法在t_tab.first中使用I。。t_tab.最后一个循环。。。端环;在稀疏集合上迭代。首先需要使用i:=t_tab;环当i=t_tab.LAST时退出;i:=t_tab.NEXTi;端环;若要执行迭代,则会出现异常,因为它将尝试访问稀疏集合中的间隙,但失败。我理解这一点,但我不能删除间隙,以便进一步迭代列表吗?我使用I:=t_tab.FIRST;环当i=t_tab.LAST时退出;i:=t_tab.NEXTi;端环;要删除该项并且eror在示例中的第二次迭代中保持不变,请使用t_tab.deletei;是完全多余的,可以删除。您正在调用t_tab.deletei;然后立即使用t_tabi:=null;-一个不存在的元素和一个空元素是两个完全不同的东西。我不是写了它吗?GAP不存在元素和null是不同的东西?正如我所说的,如果去掉t_tab.deletei;示例中的语句和代码将执行完全相同的操作。实际上,您不是在执行删除操作,而是在使用NULL进行替换,如果OP依赖于t_tab.COUNT之类的内容,这将导致错误,t_tab.COUNT将包括NULL元素,但不包括已删除元素,以了解集合的大小。它还将使所有逻辑复杂化,因为您现在必须测试集合中的每个对象是否为非null。不,我是说您不应该将任何内容设置为null,但应该使用t_tab.DELETEi;然后使用FIRST/LAST/NEXT正确地迭代稀疏集合-将things设置为NULL只不过是使用临时粘贴创建更多的工作,您需要解决这些问题。这是因为您不能使用FOR i IN t_tab.FIRST。。t_tab.最后一个循环。。。端环;在稀疏集合上迭代。首先需要使用i:=t_tab;环当i=t_tab.LAST时退出;i:=t_tab.NEXTi;端环;否则,您将获得异常,因为它将尝试访问稀疏集合中的间隙并失败;是完全多余的,可以删除。您正在调用t_tab.deletei;然后立即使用t_tabi:=null;-一个不存在的元素和一个空元素是两个完全不同的东西。我不是写了它吗?GAP不存在元素和null是不同的东西?正如我所说的,如果去掉t_tab.deletei;示例中的语句和代码将执行完全相同的操作。实际上,您不是在执行删除操作,而是在使用NULL进行替换,如果OP依赖于t_tab.COUNT之类的内容,这将导致错误,t_tab.COUNT将包括NULL元素,但不包括已删除元素,以了解集合的大小。它还将使所有逻辑复杂化,因为您现在必须测试集合中的每个对象是否为非null。不,我是说您不应该将任何内容设置为null,但应该使用t_tab.DELETEi;然后使用FIRST/LAST/NEXT正确地迭代稀疏集合-将things设置为NULL只不过是使用临时粘贴创建更多的工作,您需要解决这些问题。这是因为您不能使用FOR i IN t_tab.FIRST。。t_tab.最后一个循环。。。端环;在稀疏集合上迭代。首先需要使用i:=t_tab;环当i=t_tab.LAST时退出;i:=t_tab.NEXTi;端环;否则,您将获得异常,因为它将尝试访问稀疏集合中的间隙并失败。