【问题标题】:How to execute dynamic sql into cursor in Oracle?如何在Oracle中将动态sql执行到游标中?
【发布时间】:2018-06-21 21:50:09
【问题描述】:

我在存储过程中将动态 sql 语句执行到 sys_refcursor 时遇到问题。 我查看了文档,我认为我正确地构建了我的程序,但我仍然不知道为什么会发生错误。 请看下面,我创建了什么:

CREATE TABLE REKOM_CROSS_PROM (
      LINIA_PROD VARCHAR2(20), 
      ID_REKOM_OFERTA VARCHAR2(20),
      PRICE NUMBER,
      MAX_PRICE NUMBER
    );
/

CREATE OR REPLACE TYPE prodType AS OBJECT (
p_line VARCHAR2(20)
,p_price NUMBER
);
/

CREATE OR REPLACE TYPE prodTypeList IS TABLE OF prodType;
/

CREATE OR REPLACE PROCEDURE my_proc (prodLines IN prodTypeList ,rekom OUT SYS_REFCURSOR)
IS
v_pLine VARCHAR2(20);
v_query VARCHAR2(4000);
BEGIN
  v_query := 'SELECT ID_REKOM_OFERTA FROM REKOM_CROSS_PROM WHERE 
LINIA_PROD=NULL';
FOR i IN 1 .. prodLines.COUNT
    LOOP
        v_pLine := prodLines(i).p_line;
        v_query := v_query || ' UNION ALL SELECT ID_REKOM_OFERTA FROM 
                    REKOM_CROSS_PROM WHERE LINIA_PROD=''' || v_pLine || '''';
    END LOOP;
OPEN rekom FOR v_query;
END my_proc;
/

当我想调用该过程时,会发生错误。

set serveroutput on
    declare
    type1 prodTypeList := prodTypeList(prodType('test1',1), prodType('test2', 20));
    rc SYS_REFCURSOR;
    row varchar2(200);
BEGIN
    MY_PROC(type1, rc);
    fetch rc into row;
    while (rc%found) loop
    dbms_output.put_line(row);
end loop;
close rc;
end;

我收到消息:

ORA-20000:ORU-10027:缓冲区溢出,限制为 1000000 字节

*原因:存储过程“raise_application_error” 被调用,导致生成此错误。

*操作:按照错误消息或联系中的说明更正问题 应用程序管理员或 DBA 了解更多信息。

有人可以帮我解决问题吗?

【问题讨论】:

  • 该错误仅表示您超出了 dbms_output 缓冲区。您期望构造的查询找到多少行? (为什么要构建这样的查询而不是在查询中使用值的集合?另外:=NULL 永远不会正确,您需要IS NULL。)
  • @AlexPoole 我希望只有 3 行。我没有使用集合,因为我将在 REKOM_CROSS_PROM(价格,max_price 编号)中添加其他列,然后我将更改 WHERE 子句以添加:'AND p_price BETWEEN PRICE AND MAX_PRICE。所以当我添加这个时,我不能使用这样的集合:WHERE LINIA_PROD IN (SELECT p_line FROM prodLines)
  • 我不明白为什么你仍然不能使用集合,但也许我错过了一些东西。反正题外话……

标签: sql oracle stored-procedures plsql cursor


【解决方案1】:

你有一个无限循环。这意味着您将永远调用dbms_output.put_line - 或者直到它用完缓冲区空间并引发该异常。

BEGIN
  MY_PROC(type1, rc);
  -- fetch first row from result set
  fetch rc into row;
  -- check if last fetch found something - always true
  while (rc%found) loop
    dbms_output.put_line(row);
  end loop;
  close rc;
end;

每次循环时,您都会检查第一次获取的结果,该结果保持正确(假设有任何数据)。您需要每次循环获取:

BEGIN
  MY_PROC(type1, rc);
  -- fetch first row from result set
  fetch rc into row;
  -- check if last fetch found something
  while (rc%found) loop
    dbms_output.put_line(row);
    -- fetch next row from result set
    fetch rc into row;
  end loop;
  close rc;
end;

或者更常见的是,只在循环内获取,当没有找到时停止,使用%notfound而不是%found

BEGIN
  MY_PROC(type1, rc);
  loop
    -- fetch row from result set
    fetch rc into row;
    -- check if last fetch found something
    exit when rc%notfound;
    dbms_output.put_line(row);
  end loop;
  close rc;
end;

与您当前的问题无关,但谓词WHERE LINIA_PROD=NULL 永远不会为真; null 不等于(或不等于)其他任何东西。您需要改用WHERE LINIA_PROD IS NULL

【讨论】:

  • 我没注意到 :D 谢谢你的鹰眼 :)
猜你喜欢
  • 2011-01-10
  • 2014-04-08
  • 2014-11-20
  • 1970-01-01
  • 1970-01-01
  • 2018-01-16
  • 2018-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多