Oracle:使用动态SQL需要正确的光标记录TYPE

时间:2014-12-17 20:07:08

标签: oracle plsql

我正在尝试评估表之间现有父子关系的基数。我存储有关元数据中关系的信息,并将构建动态SQL来评估每个关系。我的结果将如下所示:

CHILD_CNT       COUNT(*)
---------     ----------
        0              3
        1              2
        2              3
        3              5
        4              8
        5              4
        7              3
       11              1

这意味着有三个父母"没有儿童记录,两个有一个孩子等。

我试过的代码看起来像这样:

procedure check_card_for_relship as

  vStmt         varchar2(32760 byte);
  type vRefCursor is ref cursor;
  cChildCntCursor vRefCursor;
  rChildCntCursor t_child_cnt;

begin
    -- The SQL statement will actually be built from a 
    -- metadata database, but this is an example of how 
    -- a finished query would look.
  vStmt := '
    select
      child_cnt
      , count(*)
    from
      (
        select
          p.empid
          , (
              select count(*)
              from pilot_training_recs c -- Child table
              where c.empid = p.empyid
            ) child_cnt
        from
          employee p  -- Parent Table
        where
          p.is_pilot_flag = 1
      )
      group by child_cnt
      order by child_cnt
    ';

  open cChildCntCursor for vStmt;
  loop
    fetch cChildCntCursor into rChildCntCursor;
    exit when cChildCntCursor%notfound;
    --
    -- My processing here...
    --
  end loop;
  close cChildCntCursor;

end check_card_for_relship;

类型t_child_cnt以这种方式定义:

create or replace type t_child_cnt as object 
  (
      cardinality_value number
    , cardinality_cnt number
  );

由于child_cnt值是子查询中的计数(),外部计数()是计数的计数,我认为可能这些都是数字的数据类型。要么不对,要么我做错了。我的错误是:

ORA-00932: inconsistent datatypes: expected - got -
ORA-06512: at "METADATA_MANIPULATION", line 36
ORA-06512: at line 6

我找不到预期的" - "但得到了" - "太有帮助了!我可能正在使用ref cursor错误。我没有经验。但是根据我的阅读,这是在使用动态SQL时定义游标的常用方法。这些例子都依赖于现有表格中的记录类型,这不符合我的情况。谢谢。

1 个答案:

答案 0 :(得分:0)

您正在尝试将记录提取到对象中。

尝试

select 
     t_child_cnt(child_cnt, count(*)) 
   from

而不是

select
      child_cnt
      , count(*)
    from

此类查询将返回对象类型的1列,因此这应该有效。

您也可以使用查询,但将结果提取到2个数字变量中。 或者为此查询创建显式游标并记录此cursor_name%rowtype, 像

CURSOR cChildCntCursor IS SELECT ... your query here;
rChildCntCursor cChildCntCursor%ROWTYPE;

比你有能力获取。

但更简单的方法是使用隐式游标,如:

For res in (SELECT child_cnt , count(*) as cnt ... your query here)
Loop
--your processing here
end loop; 

在这种情况下,您不需要声明res变量。

它将自动声明为带有字段child_cnt和cnt的记录(您可以在查询中使用其他别名,然后您将拥有另一个字段名称)。 你也不需要打开,获取和关闭这个游标 - 它是隐式完成的。

在您的情况下,使用静态SQL而不是动态(在代码中编写SQL而不是在字符串文字中)更有用。

它将在编译时检查并将访问依赖项。

动态SQL是强大的工具,适用于yhou在编译时不知道您的查询的情况,因为它依赖于某些运行时参数(我可以看到,这不是您的情况)。但是在编译时没有检查它,Oracle无法跟踪动态SQL的依赖关系,所以安全性要低得多。