迭代Oracle中的对象表

时间:2018-05-30 10:05:58

标签: oracle plsql

我应该如何迭代这样的对象表?

CREATE TYPE SOME_OBJECT AS OBJECT (
  ATTR1 VARCHAR2(20)
, ATTR2 VARCHAR2(30)
);
/

CREATE TYPE C_SOME_OBJECT AS TABLE OF SOME_OBJECT;
/

并且...我想将此作为过程的参数。必须在程序中初始化它吗?

PROCEDURE SOME_PROCEDURE(OBJECT IN C_SOME_OBJECT)
IS
BEGIN
  --Some code here iterating IN parameter
END;

2 个答案:

答案 0 :(得分:3)

-- NOTE #1
-- You cant use Object as name for your input variable because it is a type
-- (Types are reserved words)
PROCEDURE SOME_PROCEDURE(p_SOME_TABLE IN C_SOME_OBJECT)
IS
BEGIN
  FOR i IN p_SOME_TABLE.FIRST .. p_SOME_TABLE.LAST
  LOOP
     -- NOTE #2 Manage it like this
     -- Current iteration: p_SOME_TABLE(i)
     -- Access Example   : p_SOME_TABLE(i).ATTR1

     -- NOTE #3 Or you can assign current iteration to a variable
     -- then use that variable thought it is not by reference if you
     -- do it like this.
  END LOOP;
END;

<强>更新

另外注意不要将RECORDS与OBJECTS混淆。

OBJECT是一种SQL类型,但另一方面,RECORD是PL / SQL类型,你可以把它想象成类似于C / C ++的结构。

<强> UPDATE_2:

请注意,如果表为空,这不会引发任何异常,因此如果没有数据则需要处理,例如,您可以像这样使用.COUNT:

IF p_SOME_TABLE.COUNT = 0 THEN
   RAISE my_exception;
END IF;

答案 1 :(得分:2)

您可以使用WHILE循环FIRSTNEXTLAST来处理稀疏集合(元素已被删除),还需要检查未初始化集合中的元素:

PROCEDURE SOME_PROCEDURE(
  I_OBJECT IN C_SOME_OBJECT
)
IS
  i PLS_INTERGER;
BEGIN
  -- Check that the collection is not NULL
  IF I_OBJECT IS NULL THEN
    RETURN;
  END IF;

  i := I_OBJECT.FIRST;
  WHILE i IS NOT NULL LOOP
    IF I_OBJECT(i) IS NOT NULL THEN
      DBMS_OUTPUT.PUT_LINE( i || ' = (' I_OBJECT(i).attr1 || ', ' || I_OBJECT(i).attr2 || ')' );
    ELSE
      DBMS_OUTPUT.PUT_LINE( i || ' IS NULL' );
    END;
  END LOOP;
END;
/

然后你可以打电话给它:

DECLARE
  o C_SOME_OBJECT := C_SOME_OBJECT();
BEGIN
  o.EXTEND(4);
  o(1) := SOME_OBJECT( '1.1', '1.2' );
                                       -- o(2) IS NULL
  o.DELETE(3);                         -- o(3) has been removed
  o(4) := SOME_OBJECT( '4.1', '4.2' );

  SOME_PROCEDURE( o );
END;
/

输出:

1 = (1.1, 1.2)
2 IS NULL
4 = (4.1, 4.2)

FOR ... LOOP 的问题:

使用FOR i IN 1 .. o.COUNT LOOP

DECLARE
  o C_SOME_OBJECT := C_SOME_OBJECT(
                       SOME_OBJECT( '1.1', '1.2' ),
                       SOME_OBJECT( '2.1', '2.2' ),
                       SOME_OBJECT( '3.1', '3.2' ),
                       SOME_OBJECT( '4.1', '4.2' )
                     );
BEGIN
  o.DELETE(1);

  FOR i IN 1 .. o.COUNT LOOP
    IF I_OBJECT(i) IS NOT NULL THEN
      DBMS_OUTPUT.PUT_LINE( i || ' = (' I_OBJECT(i).attr1 || ', ' || I_OBJECT(i).attr2 || ')' );
    ELSE
      DBMS_OUTPUT.PUT_LINE( i || ' IS NULL' );
    END;
  END LOOP;
 END;
 /

输出:

1 IS NULL
2 = (2.1, 2.2)
3 = (3.1, 3.2)

这输出元素1,它不存在,并且不输出确实存在的元素4.

使用FOR i IN o.FIRST .. o.LAST LOOP

DECLARE
  o C_SOME_OBJECT := C_SOME_OBJECT(
                       SOME_OBJECT( '1.1', '1.2' ),
                       SOME_OBJECT( '2.1', '2.2' ),
                       SOME_OBJECT( '3.1', '3.2' ),
                       SOME_OBJECT( '4.1', '4.2' )
                     );
BEGIN
  o.DELETE(2);

  FOR i IN o.FIRST .. o.LAST LOOP
    IF I_OBJECT(i) IS NOT NULL THEN
      DBMS_OUTPUT.PUT_LINE( i || ' = (' I_OBJECT(i).attr1 || ', ' || I_OBJECT(i).attr2 || ')' );
    ELSE
      DBMS_OUTPUT.PUT_LINE( i || ' IS NULL' );
    END;
  END LOOP;
 END;
 /

输出:

1 = (1.1, 1.2)
2 IS NULL
3 = (3.1, 3.2)
4 = (4.1, 4.2)

o.COUNT仅为3时,这会输出4个元素(包括删除的第2个元素)。