如何在 SQL 中检索 PL/SQL 记录类型?
How to retrieve PL/SQL record type in SQL?
存在一个共享包,它定义了一个学生记录类型和一个函数,returns一个学生:
CREATE OR REPLACE PACKAGE shared.student_utils IS
--aggregates related data from several tables
TYPE student_rec IS RECORD (
id student.id%TYPE,
username student.username%TYPE,
name student.name%TYPE,
phone phone.phone%TYPE
/*etc.*/
);
FUNCTION get_student(student_id IN student.id%TYPE) RETURN student_rec;
END;
现在,我正在编写一个包,它提供 API 供 Apex 应用程序使用。特别是,我需要以可以通过 SQL 编辑的格式提供学生记录和其他相关数据(并显示在 Apex 的报告页面中。)
到目前为止,我一直在尝试找到 select SQL 中数据的最直接方法。显然,记录类型不能在 SQL 中使用,所以我的快速想法是在我的包规范中定义一个 table 类型,在我的包 [=] 中定义一个 PIPELINED
函数37=]:
CREATE OR REPLACE PACKAGE my_schema.api IS
TYPE student_tab IS TABLE OF shared.student_utils.student_rec;
FUNCTION get_all_student_data(student_id IN student.id%TYPE) RETURN student_tab PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY my_schema.api IS
FUNCTION get_all_student_data(student_id IN student.id%TYPE) RETURN student_tab PIPELINED IS
BEGIN
PIPE ROW(shared.student_utils.get_student(student_id));
END;
END;
...这让我 select 像这样:
SELECT * FROM TABLE(my_schema.api.get_all_student_data(1234));
这行得通,但是只为一行构建流水线 table 太过分了,而且 Oracle 的解释计划似乎也同意。
据说在 Oracle 12c 中,应该有更多可用选项:
More PL/SQL-Only Data Types Can Cross PL/SQL-to-SQL Interface
...但我似乎无法在我的场景中弄明白。将函数更改为:
FUNCTION get_all_student_data RETURN student_tab IS
r_student_tab student_tab;
BEGIN
r_student_tab(1) := shared.student_utils.get_student(student_id);
RETURN r_student_tab;
END;
...会编译,但我不能像以前那样从中SELECT
。
好的,废话不多说了,这是我的实际问题 - 调用 PL/SQL 函数的最直接方法是什么 returns 记录类型和 select/manipulate [=] 中的结果45=]?
杀手锏in the documentation是这条:
A PL/SQL function cannot return a value of a PL/SQL-only type to SQL.
这似乎排除了直接从 returns 一个 PL/SQL 记录或关联数组的函数查询,如下所示:
select * from table(student_utils.get_students(7890));
这是有效的,技术上是 SQL(因为文档将匿名块定义为 SQL 而不是 PL/SQL):
declare
ltab student_utils.students_tab;
lrec student_utils.student_rec;
rc sys_refcursor;
begin
ltab := student_utils.get_students(1234);
open rc for select * from table(ltab);
fetch rc into lrec;
dbms_output.put_line(lrec.name);
close rc;
end;
/
这很蹩脚。我想有几次我们想要从数组中打开一个引用游标,而不是仅仅为我们用来填充数组的 SQL 打开它,但这不是最紧迫的用例。
问题是 Oracle 的内部架构:内核有用于 SQL 的 C 模块和用于 PL/SQL 的 C 模块(这就是为什么您会听到人们谈论 "context switches")。向 SQL 引擎公开更多 PL/SQL 功能需要修改接口。我们只能想象让 SQL 编译器针对 PL/SQL 数据结构的定义工作是多么困难,这些数据结构非常不稳定(每次我们 运行 create or replace package ...
.
当然这确实适用于 PIPELINED 函数,但那是因为在引擎盖下 Oracle 为函数中引用的 PL/SQL 类型创建了 SQL 类型。它不能为我们可能希望滑入 table()
调用的任意函数即时创建对象。有一天这可能是可能的,但只要考虑这个症结所在:当执行了我们的包但缺乏 CREATE TYPE 权限的用户尝试使用该函数时会发生什么?
存在一个共享包,它定义了一个学生记录类型和一个函数,returns一个学生:
CREATE OR REPLACE PACKAGE shared.student_utils IS
--aggregates related data from several tables
TYPE student_rec IS RECORD (
id student.id%TYPE,
username student.username%TYPE,
name student.name%TYPE,
phone phone.phone%TYPE
/*etc.*/
);
FUNCTION get_student(student_id IN student.id%TYPE) RETURN student_rec;
END;
现在,我正在编写一个包,它提供 API 供 Apex 应用程序使用。特别是,我需要以可以通过 SQL 编辑的格式提供学生记录和其他相关数据(并显示在 Apex 的报告页面中。)
到目前为止,我一直在尝试找到 select SQL 中数据的最直接方法。显然,记录类型不能在 SQL 中使用,所以我的快速想法是在我的包规范中定义一个 table 类型,在我的包 [=] 中定义一个 PIPELINED
函数37=]:
CREATE OR REPLACE PACKAGE my_schema.api IS
TYPE student_tab IS TABLE OF shared.student_utils.student_rec;
FUNCTION get_all_student_data(student_id IN student.id%TYPE) RETURN student_tab PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY my_schema.api IS
FUNCTION get_all_student_data(student_id IN student.id%TYPE) RETURN student_tab PIPELINED IS
BEGIN
PIPE ROW(shared.student_utils.get_student(student_id));
END;
END;
...这让我 select 像这样:
SELECT * FROM TABLE(my_schema.api.get_all_student_data(1234));
这行得通,但是只为一行构建流水线 table 太过分了,而且 Oracle 的解释计划似乎也同意。
据说在 Oracle 12c 中,应该有更多可用选项:
More PL/SQL-Only Data Types Can Cross PL/SQL-to-SQL Interface
...但我似乎无法在我的场景中弄明白。将函数更改为:
FUNCTION get_all_student_data RETURN student_tab IS
r_student_tab student_tab;
BEGIN
r_student_tab(1) := shared.student_utils.get_student(student_id);
RETURN r_student_tab;
END;
...会编译,但我不能像以前那样从中SELECT
。
好的,废话不多说了,这是我的实际问题 - 调用 PL/SQL 函数的最直接方法是什么 returns 记录类型和 select/manipulate [=] 中的结果45=]?
杀手锏in the documentation是这条:
A PL/SQL function cannot return a value of a PL/SQL-only type to SQL.
这似乎排除了直接从 returns 一个 PL/SQL 记录或关联数组的函数查询,如下所示:
select * from table(student_utils.get_students(7890));
这是有效的,技术上是 SQL(因为文档将匿名块定义为 SQL 而不是 PL/SQL):
declare
ltab student_utils.students_tab;
lrec student_utils.student_rec;
rc sys_refcursor;
begin
ltab := student_utils.get_students(1234);
open rc for select * from table(ltab);
fetch rc into lrec;
dbms_output.put_line(lrec.name);
close rc;
end;
/
这很蹩脚。我想有几次我们想要从数组中打开一个引用游标,而不是仅仅为我们用来填充数组的 SQL 打开它,但这不是最紧迫的用例。
问题是 Oracle 的内部架构:内核有用于 SQL 的 C 模块和用于 PL/SQL 的 C 模块(这就是为什么您会听到人们谈论 "context switches")。向 SQL 引擎公开更多 PL/SQL 功能需要修改接口。我们只能想象让 SQL 编译器针对 PL/SQL 数据结构的定义工作是多么困难,这些数据结构非常不稳定(每次我们 运行 create or replace package ...
.
当然这确实适用于 PIPELINED 函数,但那是因为在引擎盖下 Oracle 为函数中引用的 PL/SQL 类型创建了 SQL 类型。它不能为我们可能希望滑入 table()
调用的任意函数即时创建对象。有一天这可能是可能的,但只要考虑这个症结所在:当执行了我们的包但缺乏 CREATE TYPE 权限的用户尝试使用该函数时会发生什么?