Oracle内部加入收藏?

时间:2013-01-29 13:15:54

标签: oracle plsql

我希望在以下示例中将表类型的集合与其他表联系起来 -

我有一个函数F_GetPendingFeeds,它返回feed_log类型的表集合。 我想加入这个返回的集合,其中一个表 -

CREATE OR REPLACE PACKAGE BODY L_DemoPkg
IS
   TYPE t_feedLog IS TABLE OF feed_log%ROWTYPE
                INDEX BY PLS_INTEGER;

   FUNCTION F_GetPendingFeeds
      RETURN t_feedLog
   IS
   lo_feedLog t_feedLog;
   BEGIN
      SELECT feed_log_seq
         , processed_dt
         , processed_by
         , create_dt
         , created_by
      BULK COLLECT INTO lo_feedLog
      FROM feed_log
      WHERE status_cd = 0;

      RETURN lo_feedLog;

   EXCEPTION
      WHEN OTHERS THEN
         --TODO: Log Exception
         RAISE;
   END F_GetPendingFeeds;


   PROCEDURE P_ProcessFeed
   IS
   o_pendingFeed t_feedLog;
   ln_totalRecords t_feedLog;

   BEGIN

      -- Get the list of pending feed ids
      o_pendingFeed := F_GetPendingFeeds();

      -- Check if new data is present for processing
      IF o_pendingFeed.COUNT = 0 THEN
         dbms_output.put_line('Feed processing failed. No data found.');
         RETURN;
      END IF;

      SELECT COUNT(*)
      INTO ln_totalRecords
      FROM  feed_details t1
          , table(o_pendingFeed) t2 --ERROR: ORA-22905: cannot access rows from a non-nested table item
      WHERE t1.feed_log_seq = t2.feed_log_seq;

   EXCEPTION
      WHEN OTHERS THEN
         --TODO: Log Exception
         RAISE;
   END P_ProcessFeed;
END;

我收到错误 -

PL/SQL: SQL Statement ignored
PL/SQL: ORA-22905: cannot access rows from a non-nested table
     item

请注意我想加入收藏表 -

  FROM  feed_details t1
      , table(o_pendingFeed) t2 --ERROR: ORA-22905: cannot access rows from a non-nested table item   WHERE t1.feed_log_seq = t2.feed_log_seq;

2 个答案:

答案 0 :(得分:6)

在Oracle 12C之前,您只能选择使用CREATE TYPE在服务器上创建的集合,例如

SQL> CREATE TYPE r_feedLog IS OBJECT (foo NUMBER, bar VARCHAR2(20));
SQL> CREATE TYPE t_feedLog IS TABLE OF r_feedLog;

然后从您的包中删除t_feedLog的声明。

使用Oracle 12C, 可以从包规范中定义的PL / SQL表中进行选择。

答案 1 :(得分:5)

这里有几个错误。首先,要访问TABLE转换中的数组,您需要使用SQL数组(好吧,您仍然可以使用PL / SQL表,但这仅适用于流水线函数,因为Oracle将创建SQL类型默默地为你服务;但即使在那种情况下,它仍然更整洁地使用SQL数组)。所以你需要这样做:

SQL> create type r_feedlog is object
  2  (
  3    feed_log_seq number,
  4     processed_dt date,
  5    processed_by varchar2(10),
  6    create_dt date,
  7    created_by varchar2(10)
  8  );
  9  /

Type created.

SQL> create type t_feedLog as table of r_feedlog;
  2  /

Type created.

然后使用它而不是pl / sql索引表。其次

   ln_totalRecords t_feedLog;

应该是一个数字而不是一个集合作为您的选择计数(*)。另外:

  BULK COLLECT INTO lo_transferFeedDef

应该是

  BULK COLLECT INTO lo_feedLog 

你当然可以使用流水线功能,例如:

CREATE OR REPLACE PACKAGE L_DemoPkg
as
  type r_feedlog is record(feed_log_seq number,
                           processed_dt date,
                           processed_by varchar2(10),
                           create_dt date,
                           created_by varchar2(10));
  type t_feedLog is table of r_feedlog;

  function F_GetPendingFeeds return t_feedLog pipelined;

  procedure P_ProcessFeed;
end;
/

并在包体内:

FUNCTION F_GetPendingFeeds
   RETURN t_feedLog pipelined
IS
lo_feedLog r_feedlog;
BEGIN
   for r_row in (SELECT feed_log_seq
                        , processed_dt
                        , processed_by
                        , create_dt
                        , created_by
                   FROM feed_log
                  WHERE status_cd = 0)
   loop
     lo_feedLog.feed_log_seq := r_row.feed_log_seq;
     lo_feedLog.processed_dt := r_row.processed_dt;
     lo_feedLog.processed_by := r_row.processed_by;
     lo_feedLog.create_dt := r_row.create_dt;
     lo_feedLog.created_by := r_row.created_by;
     pipe row(lo_feedLog);
   end loop;
END F_GetPendingFeeds;

在程序中你可以只是:

SELECT COUNT(*)
INTO ln_totalRecords
FROM  feed_details t1
    , table(F_GetPendingFeeds()) t2
WHERE t1.feed_log_seq = t2.feed_log_seq;

以上是保持pl / sql数组。如果你有SQL数组,那么函数会更紧凑:

FUNCTION F_GetPendingFeeds
   RETURN t_feedLog pipelined
IS
BEGIN
   for r_row in (SELECT r_feedlog(feed_log_seq
                        , processed_dt
                        , processed_by
                        , create_dt
                        , created_by) data
                   FROM feed_log
                  WHERE status_cd = 0)
   loop
     pipe row(r_row.data);
   end loop;
END F_GetPendingFeeds;