在PL / SQL块中定义引用其自身集合的记录类型

时间:2018-10-01 10:54:04

标签: oracle plsql forward-declaration hoisting

如何在PL / SQL匿名块中定义一个包含其自身集合的属性的记录类型?看下面的例子:

DECLARE
    type t_item is record (
        name varchar2(64),
        children t_items              -- referencing t_items type
    );
    type t_items is table of t_item;  -- referencing t_item type

BEGIN
    -- script code
END

PL / SQL没有类型提升,因此Oracle引擎引发异常:

  

PLS-00498:在声明类型之前非法使用该类型

如何定义在其属性t_item中包含table of t_item的记录children

3 个答案:

答案 0 :(得分:3)

您可以使用通过继承在SQL作用域中定义的对象:

SQL Fiddle

Oracle 11g R2架构设置

CREATE TYPE abstract_item IS OBJECT (
  name VARCHAR2(64)
) NOT FINAL NOT INSTANTIABLE
/

CREATE TYPE t_items IS TABLE OF abstract_item
/

CREATE TYPE t_item UNDER abstract_item (
  children t_items
) INSTANTIABLE
/

查询1

SELECT t_item(
         '1',
         t_items(
           t_item( '1.1', t_items() ),
           t_item(
             '1.2',
             t_items(
               t_item( '1.2.1', null )
             )
           ),
           t_item( '1.3', null )
         )
       )
FROM   DUAL

Results :( SQLFiddle不能很好地显示它-但它运行时没有错误)

| T_ITEM('1',T_ITEMS(T_ITEM('1.1',T_ITEMS()),T_ITEM('1.2',T_ITEMS(T_ITEM('1.2.1',NULL))),T_ITEM('1.3',NULL))) |
|-------------------------------------------------------------------------------------------------------------|
|                                                                                  oracle.sql.STRUCT@2a094aab |

您可以在PL / SQL中使用类似的声明:

DECLARE
  items t_item;
BEGIN
  items = t_item( 'Item Name', t_items( /* ... */ ) );
END;
/

答案 1 :(得分:2)

有关对象的示例:

create or replace type item; -- forward declaration 
/
create or replace type l_item_ref is table of ref item;
/
create or replace type item  is object( a number, list l_item_ref)
/
CREATE TABLE t_item OF item nested table list store as ref_items
/
declare 

  v_list l_item_ref;

begin 

insert into t_item values(1,null);
insert into t_item values(2,null);
insert into t_item values(3,null);
select ref(p) bulk collect into v_list  from t_item p;

insert into t_item values(123,v_list);
 commit;
end;

select p.a,p.list from t_item p;

答案 2 :(得分:0)

下面是创建自定义记录类型,然后使用自定义记录类型创建表类型的示例。

在您的规格文件中,您可以按以下定义自定义类型。

TYPE STUDENT IS RECORD
    ("ID" NUMBER, 
     "NAME" VARCHAR2(100)
    );
TYPE STUDENT_TABLE IS TABLE OF STUDENT;

现在,在包主体中,您可以使用如下定义的自定义表。

students STUDENT_TABLE; (Declaration of variable of type student_table)

由于它不能用作表,因此不能直接插入。还有一点要记住,如在表中,如果您一个接一个地插入记录,则基本上会创建一个新条目,但如果使用自定义记录类型,则会替换旧记录。

**SELECT
      123 AS ID,
      abc AS NAME
      BULK COLLECT INTO STUDENT_TABLE FROM DUAL;** --(This is how we insert)

考虑一下,如果我们再次执行具有不同值的同一条语句,它将如上所述覆盖前一条。

因此,如果您需要附加记录,则可以采用以下方法。

students STUDENT_TABLE;
studentsTemp STUDENT_TABLE; (Declare a temp also to store the previous value)

**SELECT
      123 AS ID,
      abc AS NAME
      BULK COLLECT INTO STUDENT_TABLE FROM DUAL;
studentsTemp := STUDENT_TABLE;

SELECT
    789 AS ID,
    xyz AS NAME
    BULK COLLECT INTO STUDENT_TABLE FROM DUAL;
studentsTemp := students multiset union all studentsTemp;** --(This is how you can append)

下面是通过游标返回它的方法。

OPEN CursorStudent FOR
    SELECT ID,
           NAME,
      FROM TABLE(studentsTemp); (Will return all records.)

使用此功能的优点是,当移至更高的环境时,可以避免使用临时表并减少要维护的脚本。