我正在尝试在oracle中创建一个存储函数,该存储函数返回多行。
除了要获取查询外,我的问题与该问题非常相似select *
简而言之,我想创建一个返回此查询结果的函数
select * from t_email_queue
Run Code Online (Sandbox Code Playgroud)
我尝试过的是:
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;
Run Code Online (Sandbox Code Playgroud)
包编译很好,但是当我尝试使用此查询调用它时
select * from table(email_queue.lock_and_get);
Run Code Online (Sandbox Code Playgroud)
Oracle引发以下错误
ORA-00902: invalid datatype
00902. 00000 - "invalid datatype"
*Cause:
*Action:
Error at Line: 1 Column: 20
Run Code Online (Sandbox Code Playgroud)
我认为Oracle希望我在架构级别创建返回类型,但是当我尝试这样做时
create type t_email_queue_type is table of T_EMAIL_QUEUE%ROWTYPE;
Run Code Online (Sandbox Code Playgroud)
甲骨文抱怨
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
Run Code Online (Sandbox Code Playgroud)
有人可以指出我正确的方向吗?我在这里想念什么?
谢谢阅读!
对于 SQL 类型,您无法执行 %ROWTYPE,您必须键入每一列以匹配表*。
*sys.anydataset 放在一边。但沿着这条路走下去需要复杂得多的编码。
例如,如果您的桌子是
create table foo (id number, cola varchar2(1));
Run Code Online (Sandbox Code Playgroud)
然后
create type email_queue_type is object (id number, cola varchar2(1));
/
create type t_email_queue_type as table of email_queue_type;
/
Run Code Online (Sandbox Code Playgroud)
并使用该表 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>
Run Code Online (Sandbox Code Playgroud)
如果您不特别喜欢使用SQL类型,则可以使用a sys_refcursor代替:
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;
/
Run Code Online (Sandbox Code Playgroud)
在SQL * Plus中,您可以这样称呼它:
var cur refcursor;
exec :cur := email_queue.lock_and_get;
print cur
Run Code Online (Sandbox Code Playgroud)
并且作为exec一个简单的匿名块的简写,您也可以从其他PL / SQL对象中调用它。但是,您不能做的是:
select * from table(email_queue.lock_and_get);
Run Code Online (Sandbox Code Playgroud)
我不熟悉从PHP调用函数,但是从Java您可以将其直接用作可调用语句的返回,因此根本不需要该select * from table()构造。我不知道您是否可以在PHP调用中执行匿名块(例如)begin $cur = email_queue.lock_and_get; end;,并具有$cur可以迭代的结果集?
我意识到这并不是一个完整的答案,因为PHP方面太模糊了,但是可能会给您一些想法。