ORA-01002:在Oracle中按顺序提取

时间:2019-05-29 12:36:29

标签: oracle plsql

  

ORA-01002:使用sys_refcursor时在oracle中不按顺序提取。

我期待光标中的员工列表。在我的实际场景中,我需要检查员工人数,如果人数大于零,则应使用相同的select语句。我没有尝试多次执行相同的select语句,而是尝试了以下代码段。但是我在输出游标中遇到Fetch out of sequence错误。

我的桌子:

My table

create or replace procedure sp_temp_1  (
var_job in VARCHAR2,
cur_custid out sys_refcursor
) 
AS

  /* Declare Ref Cursor */
  --cur_custid  SYS_REFCURSOR;

  /* Declare Type using Fields from the employees table. */
  TYPE t_custrec IS RECORD (
    firstname    temp_emp.firstname%TYPE,
    lastname     temp_emp.lastname%TYPE
  );

  /* Declare Record based off of Type */
  custrec   t_custrec;

BEGIN

  OPEN cur_custid FOR
    SELECT DISTINCT firstname
                   ,lastname
      FROM temp_emp
     WHERE JOB = var_job; /* Data Analyst does not exist forcing Zero Rows returned */

  LOOP
    FETCH cur_custid
      INTO custrec;
    EXIT WHEN cur_custid%notfound;
    ---looping happens
  END LOOP;

  dbms_output.put_line('Num Rows: ' || cur_custid%rowcount);

  IF cur_custid%rowcount = 0
  THEN
  dbms_output.put_line('Zero Rows Condition Met.  Opening Cursor.');
    OPEN cur_custid FOR
      SELECT '0' AS empid FROM dual;
  END IF;

END;

我希望有员工列表,但是sys_refcursor在Oracle中提供了“提取顺序错误”的信息:

Screen shot of my error

2 个答案:

答案 0 :(得分:1)

我不确定为什么SQL Developer会给出该错误。尝试显示绑定的光标似乎很不高兴。不过,错误是来自该输出窗口的,而不是您的代码。

如果您手动运行与SQL工作表中的脚本完全相同的测试块,并使用客户端变量将out游标绑定到该测试块,则不会出现错误:

var cur_custid refcursor;

DECLARE
  VAR_JOB VARCHAR2(200);
  CUR_CUSTID sys_refcursor;
BEGIN
  VAR_JOB := 'teach';

  SP_TEMP_1(
    VAR_JOB => VAR_JOB,
    CUR_CUSTID => CUR_CUSTID
  );
  /* Legacy output: 
DBMS_OUTPUT.PUT_LINE('CUR_CUSTID = ' || CUR_CUSTID);
*/ 
  :CUR_CUSTID := CUR_CUSTID; --<-- Cursor
--rollback; 
END;
/

Num Rows: 3


PL/SQL procedure successfully completed.

print cur_custid

但是您也没有任何输出。 print显示光标结果,但为空。

问题确实是您在过程中消耗了游标。之后:

  LOOP
    FETCH cur_custid
      INTO custrec;
    EXIT WHEN cur_custid%notfound;
    ---looping happens
  END LOOP;

您显然遇到过cur_custid%notfound,这意味着光标中没有剩余的行。没有自动或手动的倒带设备;因此,当调用者获得对该out变量的控制权时,光标仍然为空。或者,如果您更喜欢这样考虑,则光标指针仍指向数据的末尾-没有剩余的行可以使用。 (同样,为什么此时的过程执行向导错误尚不清楚。)

您的前提:

  

我需要检查员工人数,如果人数大于零,则应使用相同的select语句。而不是多次尝试执行相同的select语句

...有缺陷。您可以做您正在做的事情,但是当您使用完游标后,必须重新打开它,它仍然会重复以下语句:

  IF cur_custid%rowcount = 0
  THEN
  dbms_output.put_line('Zero Rows Condition Met.  Opening Cursor.');
    OPEN cur_custid FOR
      SELECT '0' AS empid FROM dual;
  ELSE
  dbms_output.put_line('Non-zero Rows Condition Met.  Re-opening Cursor.');
    OPEN cur_custid FOR
    SELECT DISTINCT firstname
                   ,lastname
      FROM temp_emp
     WHERE JOB = var_job; /* Data Analyst does not exist forcing Zero Rows returned */
  END IF;

在这种情况下,您实际上只需要在循环中执行一次读取,并立即退出即可;甚至根本不循环,只需执行一个简单的提取即可。您只关心零/非零,而不关心实际的非零计数。

db<>fiddle,其中包含原始代码,带有第二个光标打开的新版本以及带有单个访存的第二个新版本。并稍加修改后的调用块即可通过dbms_output输出结果。

仅进行初始计数并确定打开哪个游标可能会更简单。

奇怪的是,两个可能的光标的列数不同。大概是什么叫它应该在游标中循环,如果它在ID列中看到零,就知道没有数据?仅使那个记录它是否处理任何行会更清洁。然后,您的过程不需要任何逻辑,只需打开一个有意义的游标-如果您真的需要一个过程来执行此操作。 (您的实际情况可能比您的示例所暗示的要完成更多的工作;在这种情况下,计数方法可能仍然更合适。)

答案 1 :(得分:0)

当我使用您的代码进行较小的修改时,没有任何错误。也许我的工作代码可以为您提供帮助?让我知道您是否有任何疑问,或者我可以进一步协助您。

摘要

  • 声明参考光标
  • 根据我的雇员表中的字段声明类型
  • 根据类型声明记录
  • 打开光标并输入Loop
  • 在循环内,使用游标获取的值填充记录。
  • 使用dbms_output显示一些输出,因此我们知道它正在工作
  • 最后,如果游标OPEN光标再次使用不同的SQL返回了零行。

员工表

enter image description here

代码

Dim Conn As ADODB.Connection

Sub Connect()

    Dim connstring As String

    Set Conn = New ADODB.Connection

    connstring = "connection string"

    Conn.Open connstring
End Sub

Public Function Quer(Param1 As String, Param2 As String, Param3 As String)

    Dim querystring1 As String
    Dim rs1 As ADODB.Recordset

    querystring1 = "Select " & Param1 & " FROM table WHERE Param2 = " & Param2 & " AND Param3 = " & Param3

    Set rs1 = New ADODB.Recordset
    rs1.Open querystring1, Conn

    Record = rs1.GetRows

    Quer = Record(0, 0)

End Function