【问题标题】:How to execute an oracle procedure with an out cursor parameter in an anonymous PL/SQL block?如何在匿名 PL/SQL 块中使用 out 游标参数执行 oracle 过程?
【发布时间】:2016-01-20 23:48:27
【问题描述】:

我正在使用 Oracle XE 的 HR 数据库学习 PL/SQL。

我创建了以下存储过程:

CREATE OR REPLACE PROCEDURE get_employees( p_country_id IN CHAR
                                         , p_emp        OUT SYS_REFCURSOR) 
IS
BEGIN

  OPEN p_emp FOR
    SELECT e.first_name
          ,e.last_name
          ,e.department_id
          ,d.department_name
          ,l.city
          ,l.state_province
      FROM employees e
     INNER JOIN departments d
        ON e.department_id = d.department_id
     INNER JOIN locations l
        ON d.location_id = l.location_id
     WHERE l.country_id = p_country_id; 
END;

我知道如何在 SQL Developer GUI 界面中执行它并查看结果。我还向Justin Caveherehere 学习了如何执行它并查看 SQL*Plus 样式的结果,如下所示:

VARIABLE CE REFCURSOR;
EXEC GET_EMPLOYEES('US', :CE);
PRINT CE;

我想在匿名 PL/SQL 块中执行存储过程并在网格中查看结果,但没有成功。

就像 Justin Cave 所建议的那样,以下执行得很好,但没有显示结果:

DECLARE
  C_EMP SYS_REFCURSOR;
BEGIN
  GET_EMPLOYEES('US', C_EMP);
END;

以下将失败:

DECLARE
  C_EMP SYS_REFCURSOR;
  L_REC C_EMP%ROWTYPE; --THIS LINE FAILS.
BEGIN
  GET_EMPLOYEES('US', C_EMP);
  -- LOOP AND FETCH GOES HERE.
END;

错误信息说:

PLS-00320:此表达式类型的声明是 不完整或格式错误

我不明白。我一直在其他一些匿名 PL/SQL 块中这样做,并且效果很好。这里的那条线有什么问题?想不通。

【问题讨论】:

  • 引用游标与普通游标不同;您在其他块中到底在做什么 - 使用普通游标的 rowtpe? You can't do this,但我不确定这样做对你有什么帮助。而且我不完全确定您的问题是什么-只是为什么会出现该错误,或​​者您是否正在寻找如何在网格视图中获取参考光标?还是别的什么?
  • This answer 还展示了一种通过代码编辑器对话框在网格中获取结果的方法。这可能是其中一个问题的重复,但不确定是哪个问题。
  • @AlexPoole:我想我确实明确了我一直在尝试做的事情:I'd like to execute the stored procedure in an anonymous PL/SQL block and see the results in a grid, but it has not been successful.
  • 是的,我说我知道如何通过 SQL Developer GUI 界面执行它,你说的代码编辑器对话框:I know how to execute it in SQL Developer GUI interface and see the results.
  • 是的,但您问的唯一实际问题是“这里的那行有什么问题?”这似乎与网格部分无关。我链接的第二个问题是否有助于网格输出?

标签: oracle plsql sys-refcursor oracle-cursor recordtype


【解决方案1】:

我认为您误解了 %ROWTYPE 的用法。当您存储表中的所有行时,您应该只使用 %ROWTYPE。不要使用 %ROWTYPE,而是创建适合您正在获取的列的数据类型的自己的类型(记录)。试试这个:

DECLARE
  C_EMP SYS_REFCURSOR;
  TYPE new_type IS RECORD(FIRST_NAME VARCHAR2(100), LAST_NAME VARCHAR2(200), DEPARTMENT_ID NUMBER, DEPARTMENT_NAME VARCHAR2(200), CITY VARCHAR2(200), STATE_PROVINCE VARCHAR2(200));
  L_REC new_type; --instead of using %ROWTYPE, use the declared type
BEGIN
  GET_EMPLOYEES('US', C_EMP);
  LOOP
 FETCH c_emp INTO l_rec;
 EXIT WHEN c_emp%NOTFOUND;

     dbms_output.put_line(l_rec.first_name||'_'||
                          l_rec.last_name||'_'||
                          l_rec.department_id||'_'||
                          l_rec.department_name||'_'||
                          l_rec.city||'_'|| 
                          l_rec.state_province);
 END LOOP;

CLOSE c_emp;
END;

【讨论】:

  • 谢谢。您是指表中的所有 吗?您是说 %rowtype 只能应用于静态游标吗?
【解决方案2】:

我确定这个问题没有简短的答案。

要了解问题所在,您应该研究什么是强类型和弱类型的引用。

Oracle DBMS 没有内置工具将引用结果放入网格中。如果您要编写一个尝试 DBMS_SQL 包和动态 PL/SQL - 绝对有可能编写一个产生您期望的结果的程序(即将任何 sys_refcursor 放入网格中)。

但是,如果您刚刚开始学习 PL/SQL,请不要现在就浪费您的时间 - 首先,获得一些经验,然后您会看到如何去做。并且只要没有发生,就使用 SQL Developer 的hack

【讨论】:

  • 感谢您让我知道没有内置工具可以将 refcursor 结果放入网格中。我在原来的帖子中确实说过,我知道如何通过 SQL Developer GUI 界面查看结果,也就是您所说的 hack。
  • @Stack0verflow,那么“网格”是什么意思?描述一个你想解决问题的“理想界面”。 PS:我看到唯一的问题“这里的那条线有什么问题?”。而且我认为,如果您得到“定义弱引用游标的 %ROWTYPE 是错误的,因为它的行类型在编译时是未知的。”这样的答案,您将不会满意。所以我问你——你想得到什么?
  • 谢谢。因此,正如我们所知,SQL Developer 能够在网格中显示 ref 游标结果集,您提到的 hack。但是 SQL Developer 不会向我们展示生成的脚本(就像 SQL Server Management Studio 一样)。所以我想问题是,SQL Developer 是如何做到的?
  • 在运行时,您可以使用DBMS_SQL.describe_columns 过程获取任何引用游标中列的类型和名称。然后使用相同的包获取行。流水线功能可以帮助将获取的结果放入网格中。我很惊讶没有关于这个主题的知名讨论。我有一个完整的问题解决方案,但我无权发布它。所以你要自己写,或者问问 SQL Developer 团队他们是怎么做的。
  • 这很有趣。谢谢。
猜你喜欢
  • 2011-01-10
  • 1970-01-01
  • 2017-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-30
  • 2015-08-25
  • 1970-01-01
相关资源
最近更新 更多