5

複数の行を返すストアド関数をオラクルで作成しようとしています。

私の質問は、クエリを取得したいことを除いて、これと非常によく似ていますselect *

一言で言えば、このクエリの結果を返す関数を作成したい

select * from t_email_queue

私が試したのはこれです:

create or replace
PACKAGE email_queue AS 

  type t_email_queue_type is table of T_EMAIL_QUEUE%ROWTYPE;  

  FUNCTION lock_and_get return t_email_queue_type;

END email_queue;

create or replace
PACKAGE BODY email_queue AS 

    FUNCTION lock_and_get RETURN t_email_queue_type AS 
      queue_obj t_email_queue_type;

      cursor c (lockid in varchar2) is select * from t_email_queue where lockedby = lockid;
      lockid varchar2(100) := 'alf';
    BEGIN

      OPEN c(lockid);
      FETCH c bulk collect INTO queue_obj;

      return queue_obj;

    END lock_and_get;

END email_queue;

パッケージは問題なくコンパイルされますが、このクエリで呼び出そうとすると

select * from table(email_queue.lock_and_get);

オラクルは次のエラーをスローします

ORA-00902: invalid datatype
00902. 00000 -  "invalid datatype"
*Cause:    
*Action:
Error at Line: 1 Column: 20

オラクルはスキーマレベルで戻り値の型を作成することを望んでいると思いますが、私がやろうとすると

create type t_email_queue_type is table of T_EMAIL_QUEUE%ROWTYPE;  

オラクルは不平を言う

Type IMAIL.T_EMAIL_QUEUE_TYPE@imail dev
Error(1): PL/SQL: Compilation unit analysis terminated
Error(2,37): PLS-00329: schema-level type has illegal reference to IMAIL.T_EMAIL_QUEUE

誰かが私を正しい方向に向けることができますか? ここで何が欠けていますか?

読んでくれてありがとう!

4

3 に答える 3

5

SQL 型を使用することに特に熱心でない場合は、sys_refcursor代わりに a を使用してこれを行うことができます。

create or replace package email_queue as 
    function lock_and_get return sys_refcursor;
end email_queue;
/

create or replace package body email_queue as 
    function lock_and_get return sys_refcursor AS 
        c sys_refcursor;
        lockid varchar2(100) := 'alf';
    begin
        open c for
            select * from t_email_queue
            where lockedby = lockid;

         return c;
    end lock_and_get;
end email_queue;
/

SQL*Plus からは、次のように呼び出すことができます。

var cur refcursor;
exec :cur := email_queue.lock_and_get;
print cur

また、exec他のPL/SQLオブジェクトからも呼び出すことができる単純な無名ブロックの省略形です。ただし、できないことは次のとおりです。

select * from table(email_queue.lock_and_get);

私は PHP から関数を呼び出すことに慣れていませんが、Java からはこれを呼び出し可能なステートメントからの戻り値として直接使用できるため、select * from table()構文はまったく必要ありません。begin $cur = email_queue.lock_and_get; end;のような匿名ブロックを PHP 呼び出しで実行し$cur、結果セットとして繰り返し処理できるかどうかはわかりません。

PHP側があまりにも曖昧であるため、これは完全な答えではないことを認識していますが、いくつかのアイデアを提供するかもしれません.

于 2012-12-12T18:53:19.190 に答える
5

SQL 型では %ROWTYPE を実行できません。テーブルと一致するように各列を入力する必要があります*。

*sys.anydataset は別として。しかし、そのルートをたどると、はるかに複雑なコーディングになります。

たとえば、テーブルが

create table foo (id number, cola varchar2(1));

それから

create type email_queue_type is object (id number, cola varchar2(1));
/
create type t_email_queue_type as table of email_queue_type;
/

そのテーブル email_queue_type_tab を関数からの出力として使用します。

ただし、現在のコードはスケーラブルではないため、パイプライン化された関数をお勧めします。

例えば:

SQL> create table foo (id number, cola varchar2(1));

Table created.

SQL>
SQL> create type email_queue_type is object (id number, cola varchar2(1));
  2  /

Type created.

SQL> create type t_email_queue_type as table of email_queue_type;
  2  /

Type created.

SQL> insert into foo select rownum, 'a' from dual connect by level <= 10;

10 rows created.

SQL>
SQL> create or replace PACKAGE email_queue AS
  2
  3
  4    FUNCTION lock_and_get return t_email_queue_type pipelined;
  5
  6  END email_queue;
  7  /

Package created.

SQL> create or replace PACKAGE BODY email_queue AS
  2
  3      FUNCTION lock_and_get RETURN t_email_queue_type pipelined AS
  4        queue_obj t_email_queue_type;
  5
  6      BEGIN
  7
  8       for r_row in (select * from foo)
  9              loop
 10                pipe row(email_queue_type(r_row.id, r_row.cola));
 11              end loop;
 12
 13      END lock_and_get;
 14
 15  END email_queue;
 16  /

Package body created.

SQL> select * from table(email_queue.lock_and_get());

        ID C
---------- -
         1 a
         2 a
         3 a
         4 a
         5 a
         6 a
         7 a
         8 a
         9 a
        10 a

10 rows selected.

SQL>
于 2012-12-12T17:29:50.957 に答える