sql - 如何在 SQL 中检索 PL/SQL 记录类型?

标签 sql oracle plsql oracle12c user-defined-types

<分区>

存在一个共享包,它定义了一个学生记录类型和一个返回学生的函数:

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;

现在,我正在编写一个包,为 Apex 应用程序提供 API 以供使用。特别是,我需要以可以通过 SQL 选择的格式提供学生记录和其他相关数据(并显示在 Apex 的报告页面中。)

到目前为止,我一直在努力寻找在 SQL 中选择数据的最直接方法。显然,记录类型不能在 SQL 中使用,所以我的快速而肮脏的想法是在我的包规范中定义一个表类型,并在我的包规范/主体中定义一个 PIPELINED 函数:

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 * FROM TABLE(my_schema.api.get_all_student_data(1234));

这行得通,但是只为一行构建流水线表太过分了,而且 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 函数并在 SQL 中选择/操作结果的最直接方法是什么?

最佳答案

killer 线in the documentation是这个吗:

A PL/SQL function cannot return a value of a PL/SQL-only type to SQL.

这似乎排除了直接从返回 PL/SQL 记录或关联数组的函数进行查询,如下所示:

select * from table(student_utils.get_students(7890));

起作用的是这个,从技术上讲,它是 SQL(因为文档将匿名 block 定义为 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 模块(这就是为什么您会听到人们谈论“上下文切换”)。向 SQL 引擎公开更多 PL/SQL 功能需要修改接口(interface)。我们只能想象让 SQL 编译器根据极不稳定的 PL/SQL 数据结构的定义工作是多么困难(每次我们运行 create or replace package ....

当然这确实适用于 PIPELINED 函数,但那是因为在引擎盖下 Oracle 为函数中引用的 PL/SQL 类型创建了 SQL 类型。它不能为我们可能希望滑入 table() 调用的任意函数即时创建对象。有一天它可能是可能的,但只要考虑这个症结所在:当一个已经执行了我们的包但缺乏 CREATE TYPE 权限的用户试图使用该函数时会发生什么?

关于sql - 如何在 SQL 中检索 PL/SQL 记录类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48472555/

相关文章:

sql - 基于 sysdate 的事件

mysql - 如何在sql中为串行数据类型的列创建外键

mysql - mysql 选择查询中的别名

mysql - 在子查询中使用表别名与 where 子句对齐

oracle - PLS-00231 : Function may not be used in SQL

oracle - 在 Oracle 中导入 .sql 文件?

java - HSQLDB 中可以有 CURSOR 类型的 OUT 参数吗?

oracle - 使用带有多个相同绑定(bind)参数的 EXECUTE IMMEDIATE

mysql - SQL strip 最长公共(public)前缀

Oracle STANDARD_HASH 在 PLSQL 中不可用?