错误发生的原因是在执行存储过程操作中,读取游标少读取了某个或者某些列。
不过,这似乎是不可能发生的,因为编译阶段都会报错。
下面演示错误的发生以及解决方法。
1.创建测试表USERS。
CREATE TABLE "USERS2" (
"USERNAME" VARCHAR2(20 BYTE),
"USERPASS" VARCHAR2(20 BYTE),
"COUNTER" NUMBER(11,0)
) ;
2.创建测试过程PROC_DEMO,故意少读取一列。
create or replace
PROCEDURE PROC_DEMO AS
uname varchar2(20);
upass varchar2(20);
counter number;
BEGIN
DECLARE CURSOR CUR_USERS is
select * from USERS;
BEGIN
OPEN CUR_USERS;
LOOP
FETCH CUR_USERS INTO uname,upass;
EXIT when CUR_USERS%NOTFOUND;
dbms_output.put_line('uname:'||uname);
dbms_output.put_line('upass:'||upass);
dbms_output.put_line('counter:'||counter);
END LOOP;
CLOSE CUR_USERS;
END;
END PROC_DEMO;
编译以上过程,发生错误:
Error(12,5): PL/SQL: SQL Statement ignored
Error(12,5): PLS-00394: 在 FETCH 语句的 INTO 列表中值数量出现错误
连编译都通不过,更不要说在执行时出现如下错误:ORA-00932: 数据类型不一致: 应为 -, 但却获得 –。
以上是在SQL Developer进行的测试。在PROC_DEMO声明游标CUR_USERS并读取,如果少读取了某个或者某些列编译通不过。如果游标CUR_USERS不是在过程中显示声明的而是通过调用返回游标类型数据的过程中获取的,那么少读取了某个或者某些列编译可能能够通过。
3.创建返回游标和基本类型数据的过程。
该过程封装在包中,包声明如下:
create or replace PACKAGE PACKAGE_TEST AS
TYPE CURSOR_TYPE IS REF CURSOR;
PROCEDURE PROC_TEST(
COUNTER OUT NUMBER,
CUR_USERS OUT CURSOR_TYPE
);
END PACKAGE_TEST;
创建包体如下:
create or replace PACKAGE BODY PACKAGE_TEST
IS
PROCEDURE PROC_TEST(
COUNTER OUT NUMBER,
CUR_USERS OUT CURSOR_TYPE
)
IS
SELECT_SQL VARCHAR2(200);
BEGIN
SELECT_SQL := 'SELECT COUNT(*) FROM USERS';
EXECUTE IMMEDIATE SELECT_SQL INTO COUNTER;
SELECT_SQL := 'SELECT USERNAME,USERPASS FROM USERS';
OPEN CUR_USERS FOR SELECT_SQL;
END PROC_TEST;
END PACKAGE_TEST;
4.创建测试过程PROC_CLIENT。
create or replace
PROCEDURE PROC_CLIENT AS
TYPE CURSOR_TYPE IS REF CURSOR;
CUR_USERS CURSOR_TYPE;
COUNTER number;
uname varchar2(20);
upass varchar2(20);
BEGIN
--调用PACKAGE_TEST中的过程PROC_TEST
PACKAGE_TEST.PROC_TEST(COUNTER,CUR_USERS);
--打印结果信息
DBMS_OUTPUT.PUT_LINE('COUNTER:'||COUNTER);
DBMS_OUTPUT.PUT_LINE('返回的游标中的数据:');
LOOP
FETCH CUR_USERS INTO uname;
EXIT when CUR_USERS%NOTFOUND;
dbms_output.put_line('uname:'||uname);
--dbms_output.put_line('upass:'||upass);
END LOOP;
CLOSE CUR_USERS;
END PROC_CLIENT;
运行PROC_CLIENT,发生如下错误:
ORA-00932: 数据类型不一致: 应为 -, 但却获得 -
ORA-06512: 在 "DEMO.PROC_CLIENT", line 14
ORA-06512: 在 line 2
原因是PACKAGE_TEST.PROC_TEST返回的游标CUR_USERS是表USERS两个列
USERNAME和USERPASS的结果集,但是在PROC_CLIENT中读取该游标时只读取了USERNAME。
解决方法:
将读取游标的语句修改为如下所示:
FETCH CUR_USERS INTO uname,userpass;
EXIT when CUR_USERS%NOTFOUND;
dbms_output.put_line('uname:'||uname);
dbms_output.put_line('upass:'||upass);
总结,通过上面的演示可以发现其实这是个很表面的错误,仅仅因为游标是从别的过程中声明并产生数据集的,所以躲过了很多编译错误,直到运行时才发生莫名其妙的错误。