如何使用游标和批量收集来填充嵌套 table(带有嵌套对象)

How to populate nested table (with nested objects) by using cursor and bulk collect

也许你知道问题出在哪里了

我有 3 种类型:

create or replace type t_money as object (
  val number(14,2)
 ,cur varchar2(3 CHAR)
);
/

create or replace type t_wallet as object (
  name   varchar2(50 CHAR)
 ,amount t_money
);
/

create or replace type t_wallets is table of t_wallet;
/

我需要使用批量收集从游标填充嵌套 table:

declare
  walletCollection t_wallets;
  cursor walletCursor is 
    select 'some name'          as name
          ,t_money(99, 'EUR')   as amount
      from dual;
begin
  open walletCursor;
  fetch walletCursor bulk collect into walletCollection;
  close walletCursor;
end;

Aaaaaaand ... 它不起作用。我收到此错误:

ORA-06550: line 9, column 40: PLS-00386: type mismatch found at 'WALLETCOLLECTION' between FETCH cursor and INTO variables

我知道我可以使用:

type walletRecords is table of walletCursor%ROWTYPE;
walletCollection walletRecords;

但在这种情况下我不能那样做,walletCollection 必须是 t_wallets 的嵌套 table。

怎么做?不匹配在哪里?

Oracle 实时脚本 https://livesql.oracle.com/apex/livesql/s/hr22zxdw7842um41u9ylnraz1

不匹配很明显:您的光标位于一组包含两列的行上,分别为 VARCHAR2T_MONEY 类型,但嵌套的 table 需要 T_WALLET。在某处,不知何故,您必须从游标中的数据构造 T_WALLET 类型的对象。

假设游标定义中的 SELECT 语句模拟具有两列的实际 table,您可以将其包装在使用构造函数的外部查询中。 (否则 table 或 SELECT 语句必须已经存储或创建 T_WALLETs。)

declare
  walletCollection t_wallets;
  cursor walletCursor is
    select t_wallet(name, amount)   -- THIS outer select, using the constructor
    from   (
             select 'some name'          as name
                  , t_money(99, 'EUR')   as amount
             from   dual
           );
begin
  open walletCursor;
  fetch walletCursor bulk collect into walletCollection;
  close walletCursor;
end;
/

这里有一个简短的演示,显示嵌套的 table 已正确填充。注意过程体中对 dbms_output.put_line 的调用;通常你只会为了开发和调试目的而做这样的事情(并且为了说明,就像在这种情况下)。确保你 运行 set serveroutput on 看到输出。

declare
  walletCollection t_wallets;
  cursor walletCursor is
    select t_wallet(name, amount) 
    from   (
             select 'some name'          as name
                  , t_money(99, 'EUR')   as amount
             from   dual
           );
begin
  open walletCursor;
  fetch walletCursor bulk collect into walletCollection;
  close walletCursor;

  for i in 1 .. walletCollection.Count loop
    dbms_output.put_line( 'Name: '       || walletCollection(i).name       || 
                          ', amount: '   || walletCollection(i).amount.val ||
                          ', currency: ' || walletCollection(i).amount.cur );
  end loop;
end;
/

Name: some name, amount: 99, currency: EUR


PL/SQL procedure successfully completed.