【问题标题】:Oracle PL/SQL collect values from a loop into a cursorOracle PL/SQL 将循环中的值收集到游标中
【发布时间】:2015-11-23 10:12:43
【问题描述】:

我有一个包含文档 ID 的 PL/SQL TABLE TYPE 结果集。
我可以毫无问题地遍历结果集,但问题是我必须从函数返回一个 sys_refcursor,但我无法将循环中的值收集到游标中。

TYPE table_typ IS TABLE OF DOCUMENT_QUEUE.ENV_ID%TYPE INDEX BY PLS_INTEGER;

FUNCTION GET_DOCS()
RETURN SYS_REFCURSOR
IS
   LS_CUR SYS_REFCURSOR;
   LR_UPDATED_ROWS table_typ;
BEGIN
      UPDATE DOCUMENT_QUEUE DQ
      ...
      RETURNING DQ.ENV_ID BULK COLLECT INTO LR_UPDATED_ROWS;               

      -- Need to collect all of the following rows into the cursor
      FOR indx IN NVL (LR_UPDATED_ROWS.FIRST, 0) .. NVL (LR_UPDATED_ROWS.LAST, -1)
      LOOP
          SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID = LR_UPDATED_ROWS(indx);
      END LOOP;

      RETURN LS_CUR;        
END GET_DOCS;

欢迎所有帮助和提示。

【问题讨论】:

  • FOR 循环中的 SQL 会出错,因为 PL/SQL 需要一个 INTO 子句。
  • 现在是的。目前它是为了展示我想要实现的目标。也许有一种方法可以在不使用循环的情况下做到这一点,但我一直找不到。
  • 是的,循环不需要光标。您可以使用 OPEN CURSOR FOR 语句。有关更多详细信息和工作演示,请参阅答案。

标签: oracle plsql cursor


【解决方案1】:
FOR indx IN NVL (LR_UPDATED_ROWS.FIRST, 0) .. NVL (LR_UPDATED_ROWS.LAST, -1)
      LOOP
          SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID = LR_UPDATED_ROWS(indx);
      END LOOP;

      RETURN LS_CUR;   

您不需要 FOR LOOP 光标。您可以使用 OPEN CURSOR FOR 语句并返回 SYS_REFCURSOR

例如,

OPEN LS_CUR FOR SELECT * FROM DOCUMENT_QUEUE DQ 
WHERE DQ.ENV_ID IN (SELECT * FROM TABLE(LR_UPDATED_ROWS));

RETURN LS_CUR; 

或者,

OPEN LS_CUR FOR SELECT * FROM DOCUMENT_QUEUE DQ 
WHERE DQ.ENV_ID MEMBER OF LR_UPDATED_ROWS;

RETURN LS_CUR; 

但是,为了做到这一点,您必须在 SQL 级别而不是在 PL/SQL 级别创建类型。否则,您将收到PLS-00642: local collection types not allowed in SQL statements

一个小演示:

SQL 级别创建类型

SQL> CREATE OR REPLACE TYPE table_typ AS TABLE OF NUMBER
  2  /

Type created.

让我们使用 refcursorSQL*Plus 中获取输出:

使用 MEMBER OF 语法

SQL> variable r refcursor
SQL> DECLARE
  2    l_typ table_typ;
  3  TYPE numbers IS TABLE OF NUMBER;
  4    n numbers;
  5  BEGIN
  6    SELECT empno BULK COLLECT INTO l_typ FROM emp;
  7    OPEN :r FOR SELECT empno,
  8    ename FROM emp WHERE empno member OF l_typ;
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL> print r

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7902 FORD
      7934 MILLER

14 rows selected.

使用TABLE函数

SQL> variable r refcursor
SQL> DECLARE
  2    l_typ table_typ;
  3  TYPE numbers IS TABLE OF NUMBER;
  4    n numbers;
  5  BEGIN
  6    SELECT empno BULK COLLECT INTO l_typ FROM emp;
  7    OPEN :r FOR SELECT empno,
  8    ename FROM emp WHERE empno IN (SELECT * from TABLE(l_typ));
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL> print r

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7902 FORD
      7934 MILLER

14 rows selected.

【讨论】:

  • 如何在不进入 SQL 级别的情况下解决这个问题?不幸的是,我无法访问 SQL 级别。有没有办法在不使用表类型的情况下解决相同的任务? (获取更新的 id 列表)
【解决方案2】:

对于上面提到的要求,我在下面提到了一个 sn-p,它将有助于将所有行提取到每个 rowid 的 ref 游标中。让我知道这是否有帮助。

CREATE OR REPLACE TYPE table_typ
IS
  TABLE OF DOCUMENT_QUEUE.ENV_ID%TYPE INDEX BY PLS_INTEGER;


CREATE OR REPLACE FUNCTION GET_DOCS
RETURN SYS_REFCURSOR
IS
  LS_CUR SYS_REFCURSOR;
  LR_UPDATED_ROWS table_typ;
  lv_rows_lst VARCHAR2(32676);
BEGIN
  SELECT <COL1> BULK COLLECT INTO LR_UPDATED_ROWS FROM <TABLE_NAME>;
  FOR I IN LR_UPDATED_ROWS.FIRST..LR_UPDATED_ROWS.LAST
  LOOP
    lv_rows_lst:=lv_rows_lst||','||LR_UPDATED_ROWS(I);
  END LOOP;
  lv_rows_lst:=SUBSTR(lv_rows_lst,2,LENGTH(lv_rows_lst));
  OPEN LS_CUR FOR 'SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID IN ('||lv_rows_lst||')';
  RETURN LS_CUR;
END GET_DOCS;

【讨论】:

  • 这是我当前问题的解决方案,因为我无法在 PL/SQL 之外创建类型,我必须从函数返回一个 SYS_REFCURSOR。
猜你喜欢
  • 2023-04-01
  • 2012-03-27
  • 2012-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多