如何传递从多个表创建的 PL/SQL 游标记录?

Posted

技术标签:

【中文标题】如何传递从多个表创建的 PL/SQL 游标记录?【英文标题】:How can I pass a PL/SQL cursor record created from multiple tables? 【发布时间】:2021-04-05 16:29:58 【问题描述】:

这是 12c 数据库中的 PL/SQL。

我需要能够将游标记录传递给函数。问题是光标来自三个不同的表,其中一个必须使用 * 来选择该表中的所有(数百个)字段。 如果我选择不同的字段(从较小的测试表中),它可以工作,如果我从一个表中使用 select * 而没有其他字段(不涉及其他表),它可以工作,但是我找不到任何方法来使这个工作从三个表中选择(示例仅显示两个)并从其中一个表中使用 *(选择所有字段)。

我已经使用预定义的游标尝试了 FETCH INTO 和 SELECT INTO。我尝试使用带有 FOR myRecord IN (SELECT a.*, ...) 的游标记录和 创建匹配对象(因为无法在架构级别创建记录)

这些工作

myVarA a%ROWTYPE;
SELECT a.* INTO myVarA  
  FROM a;

SELECT a.myAfield, b.myBfield INTO myVarA, myVarB
  FROM a, b;

但我需要这个来工作:

myVarA a%ROWTYPE;
SELECT a.*, b.myBfield  INTO myVarA, myVarB  
  FROM a, b;

使用游标记录

myRecord        myObjectTypeWithAllFields;      -- ojbect, not record as record can't be declared at schema level

FOR myRecord IN (SELECT a.*, b.myBfield FROM a, b); 
newVar  := myFunction(myRecord);        -- this won't work

使用 PLS-00306 调用函数失败:调用 myFunction 时参数的数量或类型错误;

该函数会做很多在许多包中都相似的繁琐工作,但也有大量独特的工作 在每个包中,所以我不能只处理函数中的整个游标循环。我真的需要一次将一行传递给函数。

有没有办法做到这一点?

【问题讨论】:

【参考方案1】:

你可以在包中定义一个游标——不管你是否会真正使用它——使用相同的选择列表:

create package p as
cursor c is select a.*, b.myBField
from a, b; -- but use proper join syntax
end;
/

然后使用该光标的%rowtype 定义您的函数参数:

create function myFunction(p_record p.c%rowtype) return ... as ...

那么你的块就可以工作了:

FOR myRecord IN (SELECT a.*, b.myBfield FROM a, b) LOOP
  newVar  := myFunction(myRecord);
END LOOP;

db<>fiddle demo

然后,如果您愿意,for 循环的光标可以使用包中定义的光标。


顺便说一句,在您的对象版本中,变量声明:

myRecord        myObjectTypeWithAllFields;

是多余的; FOR myRecord... 中的 myRecord 是完全独立的。所以它甚至不会尝试使用对象类型。

【讨论】:

是的,我认为明确的“myRecord”声明已被 FOR IN 语句覆盖,因此感谢您确认。在每个包中创建光标很有趣,尽管需要它的包有几十个,所以维护将是一个权衡,但也许值得。我会考虑一下。 您只需要创建一次,并且所有内容都引用该定义。 首先 - 谢谢!这有效并且完全符合我的要求。我有许多使用类似 SELECT 的包 - 它们返回相同的数据,但 WHERE 子句各不相同,虽然我不能使用公共游标,但您向我展示了如何对我的所有包执行/使用,我可以使用有代表性的游标这允许我定义它并将其用作我的函数定义中的 ROWTYPE - 现在我可以从所有包中调用我的函数。再次谢谢你。为了解决这个问题,我已经把它撞在墙上多久了,我的头很疼。【参考方案2】:

您使用的是 %rowtype 锚点,所以我假设是精确提取。 Oracle 不允许使用带有“into”子句的多条记录。但我们可以有一个解决方法。

DECLARE

  emprec EMPLOYEES%ROWTYPE;
  deptname DEPARTMENTS.department_name%type;
BEGIN

  select a.* into emprec
    from EMPLOYEES a
    WHERE EMPLOYEE_ID = 100;

  SELECT DEPARTMENT_NAME into deptname
    from DEPARTMENTS where DEPARTMENT_ID = emprec.DEPARTMENT_ID;
END;

这个例子展示了如何在一条记录中获取你的 a.* 并与另一个表进行内部连接,并将 b.myBfield 放入另一条记录中。 这些又是记录,所以我假设它是准确的。 如果这不是您想要的,请在评论中告诉我。

【讨论】:

我为这篇文章简化了我的选择,我想我可能做得过火了。实际选择因每个包而异,而且相当复杂,所以我不确定我是否可以完成这项工作(我会试一试并酌情修改我的帖子)。

以上是关于如何传递从多个表创建的 PL/SQL 游标记录?的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL-如何使用游标的所有列插入表

在 PL/SQL 过程中打开动态表名的游标

Oracle Pl/sql 从多个查询中返回一个游标

PL/SQL:从两个函数之间传递的游标中获取

如何在 PL/SQL 中创建两个表的记录类型?

如何在 PL/SQL 代码的 for 循环中创建游标并将结果批量收集到表中