如何使用oracle从存储函数中检索多行

如何使用oracle从存储函数中检索多行,oracle,plsql,Oracle,Plsql,我试图在oracle中创建一个返回多行的存储函数 我的问题与非常类似,只是我想获取一个select*查询 简而言之,我想创建一个函数,返回这个查询的结果 select * from t_email_queue select * from table(email_queue.lock_and_get); 我试过的是: create or replace PACKAGE email_queue AS type t_email_queue_type is table of T_EMAIL_

我试图在oracle中创建一个返回多行的存储函数

我的问题与非常类似,只是我想获取一个select*查询

简而言之,我想创建一个函数,返回这个查询的结果

select * from t_email_queue
select * from table(email_queue.lock_and_get);
我试过的是:

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 t_email_queue
select * from table(email_queue.lock_and_get);
Oracle抛出以下错误

ORA-00902: invalid datatype
00902. 00000 -  "invalid datatype"
*Cause:    
*Action:
Error at Line: 1 Column: 20
我认为Oracle希望我在模式级别创建返回类型,但当我尝试这样做时

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
有人能给我指一下正确的方向吗?我错过了什么


谢谢你的阅读

对于SQL类型,您不能使用%ROWTYPE,您必须键入每一列以匹配表*

*把sys.anydataset放在一边。但是沿着这条路线走下去的编码要复杂得多

e、 如果你的桌子是空的

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

并使用该表email_queue_type_选项卡作为函数的输出

但我建议使用流水线函数,因为您当前的代码不可伸缩

例如:


如果您对SQL类型不太感兴趣,可以使用sys\u refcursor:

从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表构造。我不知道是否可以在PHP调用中执行匿名块,比如begin$cur=email\u queue.lock\u和\u get;终止并将$cur作为您的结果集,然后您可以对其进行迭代


我意识到这不是一个完整的答案,因为PHP方面太模糊了,但可能会给您一些想法。

如果您使用PHP并且希望访问oracle存储函数。你可以利用这样的东西

//Your connection details
$conn = oci_connect($username, $password, '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE)))' );

/* Your query string; you can use oci_bind_by_name to bind parameters or just pass the variable in it*/

$query = "begin :cur := functionName('".$param1."','".$param2."','".$param3."'); end;";
$stid = oci_parse($conn, $query); 
$OUTPUT_CUR = oci_new_cursor($conn);
oci_bind_by_name($stid, ':cur', $OUTPUT_CUR, -1, OCI_B_CURSOR);
oci_execute($stid); 
oci_execute($OUTPUT_CUR);
oci_fetch_all($OUTPUT_CUR, $res);

// To get your result  
var_dump($res);


我希望这能有所帮助。

这个解决方案的问题是,当我必须向表t\u email\u队列中添加一列时,我还必须修改我的类型email\u queue\u type,这很痛苦;当我修改类型和包时,我必须停止我的PHP脚本调用包,这不是一个选项。@Alfwed您在11g上吗。如果是这样的话,版本就意味着你可以在不停止PHP应用程序的情况下更新type+package/type。我们大约每秒钟调用一次这个函数。您是说我可以在两次调用之间编辑表、类型和包?@Alfwed您以前遇到过表问题,但正如我所说的,对于editions,您可以在新版本中编辑类型+包,因此运行的代码无法看到它。完成后,您将其设置为活动,以便任何新呼叫都能看到它。例如,呼叫A进入,然后您在新版本中编辑类型,然后呼叫B进入。呼叫B仍将看到旧类型。我建议你读一下。我看这是个好答案。我目前正在使用这种技术,但我不太喜欢它,因为从PHP调用这种函数有点奇怪。因此,我的问题是关于表返回类型。@Alfwed-可能是一个没有意义的区别,但是在过程中返回ref游标作为out参数也是一个选项。在PHP中可能同样奇怪,但我不知道*8-
//Your connection details
$conn = oci_connect($username, $password, '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE)))' );

/* Your query string; you can use oci_bind_by_name to bind parameters or just pass the variable in it*/

$query = "begin :cur := functionName('".$param1."','".$param2."','".$param3."'); end;";
$stid = oci_parse($conn, $query); 
$OUTPUT_CUR = oci_new_cursor($conn);
oci_bind_by_name($stid, ':cur', $OUTPUT_CUR, -1, OCI_B_CURSOR);
oci_execute($stid); 
oci_execute($OUTPUT_CUR);
oci_fetch_all($OUTPUT_CUR, $res);

// To get your result  
var_dump($res);