2017-08-05 41 views
-1

我必须创建过程才能将行插入到表中,还需要包含可捕获任何错误的OUT参数。然而,当我测试使用匿名块它不会工作,但如果我在程序中使用异常它正在工作。这意味着如果我添加一个OUT参数,并且传递来自该块的值,它将无法工作。在Oracle的程序中使用OUT参数捕获错误

此代码的工作,但不是我想要的:

create or replace 
    PROCEDURE EXAM_SP 
(P_FIRSTNAME IN BB_SHOPPER.FIRSTNAME%TYPE, 
P_LASTNAME IN BB_SHOPPER.LASTNAME%TYPE, 
P_ADDRESS IN BB_SHOPPER.ADDRESS%TYPE, 
P_CITY IN BB_SHOPPER.CITY%TYPE, 
P_STATE IN BB_SHOPPER.STATE%TYPE, 
P_ZIP IN BB_SHOPPER.ZIPCODE%TYPE) 


IS 

BEGIN 
INSERT INTO BB_SHOPPER (IDSHOPPER, FIRSTNAME, LASTNAME, ADDRESS, CITY, 
STATE, ZIPCODE) 
VALUES     
(BB_SHOPPER_IDSHOPPER_SEQ.NEXTVAL,P_FIRSTNAME,P_LASTNAME,P_ADDRESS, 
         P_CITY, P_STATE,P_ZIP); 

EXCEPTION 
WHEN OTHERS THEN 
DBMS_OUTPUT.PUT_LINE('Error Code = '||SQLCODE); 
DBMS_OUTPUT.PUT_LINE('Error Message = Please check input');  
END EXAM_SP;. 

但在上面的代码,如果我的名字在参数它不会工作,不知道如何做到这一点,如果我参数添加出来的程序和传递值:

create or replace 
    PROCEDURE EXAM_SP 
(P_FIRSTNAME IN VARCHAR2, 
P_LASTNAME IN VARCHAR2, 
P_ADDRESS IN VARCHAR2, 
P_CITY IN VARCHAR2, 
P_STATE IN CHAR, 
P_ZIP IN VARCHAR2, 
P_ERROR OUT VARCHAR2)...... 

我会收到此错误

ORA-06502: PL/SQL: numeric or value error: character string buffer too small 

如果我删除参数,并使用ORI在开始工作时的金色代码。

匿名块获取错误:

DECLARE 
    LV_FIRSTNAME_TXT BB_SHOPPER.FIRSTNAME%TYPE := 'FIRST'; 
    LV_LASTNAME_TXT BB_SHOPPER.LASTNAME%TYPE := 'LAST'; 
    LV_ADDRESS_TXT BB_SHOPPER.ADDRESS%TYPE := '8899 TAPE PARK'; 
    LV_CITY_TXT BB_SHOPPER.CITY%TYPE := 'JACKSONVILLE'; 
    LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd'; 
    LV_ZIP_NUMBER BB_SHOPPER.ZIPCODE%TYPE := '34567'; 
    LV_ERROR varchar2(100); 

BEGIN 
    EXAM_SP(LV_FIRSTNAME_TXT, LV_LASTNAME_TXT, LV_ADDRESS_TXT,  
    LV_CITY_TXT,LV_STATE_TXT,LV_ZIP_NUMBER); 

    DBMS_OUTPUT.PUT_LINE(LV_ERROR); 
END; 

步骤:

create or replace 
    PROCEDURE EXAM_SP 
(P_FIRSTNAME IN VARCHAR2, 
P_LASTNAME IN VARCHAR2, 
P_ADDRESS IN VARCHAR2, 
P_CITY IN VARCHAR2, 
P_STATE IN CHAR, 
P_ZIP IN VARCHAR2, 
P_ERROR OUT VARCHAR2) 



IS 

BEGIN 
    INSERT INTO BB_SHOPPER (IDSHOPPER, FIRSTNAME, LASTNAME, ADDRESS, CITY, 
         STATE, ZIPCODE) 
    VALUES     
     (BB_SHOPPER_IDSHOPPER_SEQ.NEXTVAL,P_FIRSTNAME,P_LASTNAME,P_ADDRESS, 
         P_CITY, P_STATE,P_ZIP); 

EXCEPTION 
    WHEN OTHERS THEN 
    P_ERROR := SQLCODE; 

/*DBMS_OUTPUT.PUT_LINE('Error Code = '||SQLCODE); 
DBMS_OUTPUT.PUT_LINE('Error Message = Please check input'); 
P_ERROR := SQLCODE;*/ 

END EXAM_SP; 
,我接收

错误消息:

Error report: 
ORA-06502: PL/SQL: numeric or value error: character string buffer too small 
ORA-06512: at line 6 
06502. 00000 - "PL/SQL: numeric or value error%s" 

我已经在通过可变'FLd'到过程参数为了测试错误捕获。

表结构:

IDSHOPPER NUMBER(4,0) 
FIRSTNAME VARCHAR2(15 BYTE) 
LASTNAME VARCHAR2(20 BYTE) 
ADDRESS VARCHAR2(40 BYTE) 
CITY VARCHAR2(20 BYTE) 
STATE CHAR(2 BYTE) 
ZIPCODE VARCHAR2(15 BYTE) 
PHONE VARCHAR2(10 BYTE) 
FAX VARCHAR2(10 BYTE) 
EMAIL VARCHAR2(25 BYTE) 
USERNAME VARCHAR2(8 BYTE) 
PASSWORD VARCHAR2(8 BYTE) 
COOKIE NUMBER(4,0) 
DTENTERED DATE 
PROVINCE VARCHAR2(15 BYTE) 
COUNTRY VARCHAR2(15 BYTE) 
... 
+1

为什么你想要使用一个out参数,而不是让调用者直接看到异常(并且还看到错误堆栈)?无论如何,你不清楚你有什么问题;为什么不告诉我们*不工作的代码以及你使用该代码的错误或问题? –

+0

我想在这个实例中传回给匿名块并打印出来,或作为提示显示给用户。如果我参数添加出来的过程,我传递值,我会收到此错误:创建或替换 PROCEDURE EXAM_SP (P_FIRSTNAME IN VARCHAR2, P_LASTNAME IN VARCHAR2, P_ADDRESS IN VARCHAR2, P_CITY IN VARCHAR2, P_STATE在煤焦, P_ZIP IN VARCHAR2, P_ERROR OUT VARCHAR2)....... – DKCroat

+1

请[编辑您的问题](https://stackoverflow.com/posts/45523242/edit)显示您的完整新程序*和*匿名块您正在使用;和错误堆栈跟踪,以便我们可以确切地看到抛出异常的位置。 –

回答

3

错误堆栈显示:

ORA-06502: PL/SQL: numeric or value error: character string buffer too small 
ORA-06512: at line 6 
06502. 00000 - "PL/SQL: numeric or value error%s" 

即堆栈显示,部分是因为它没有提到的程序名称,该错误是从的6线匿名块。它没有达到该区块第11行程序的呼叫程度。

的问题是,您已经定义了状态变:使用%TYPE语法,这是伟大的

LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd'; 

;但是由于表列是char(2),当您尝试将三字符文本字面值'Fld'分配给该双字符局部变量时,它立即在该点发生错误。

越来越远送三字符值的过程,所以你从insert期待错误不会出现,因为insert没有任何发生。

如果你想与特定的错误,打破它,你可以改变局部变量声明为固定的长度,而不是使用%TYPE,你通常会想:

DECLARE 
    LV_FIRSTNAME_TXT BB_SHOPPER.FIRSTNAME%TYPE := 'FIRST'; 
    LV_LASTNAME_TXT BB_SHOPPER.LASTNAME%TYPE := 'LAST'; 
    LV_ADDRESS_TXT BB_SHOPPER.ADDRESS%TYPE := '8899 TAPE PARK'; 
    LV_CITY_TXT BB_SHOPPER.CITY%TYPE := 'JACKSONVILLE'; 
    --LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd'; 
    -- specific length to allow invalid value to be used 
    LV_STATE_TXT char(3) := 'FLd'; 
    LV_ZIP_NUMBER BB_SHOPPER.ZIPCODE%TYPE := '34567'; 
    LV_ERROR varchar2(100); 

BEGIN 
    EXAM_SP(LV_FIRSTNAME_TXT, LV_LASTNAME_TXT, LV_ADDRESS_TXT,  
    LV_CITY_TXT,LV_STATE_TXT,LV_ZIP_NUMBER,LV_ERROR); 

DBMS_OUTPUT.PUT_LINE(LV_ERROR); 
END; 
/

-12899 

PL/SQL procedure successfully completed. 

或者更简单地使用文字直接为IN参数,因为你只是测试的过程。在这一点上:

DECLARE 
    LV_ERROR varchar2(100); 
BEGIN 
    EXAM_SP('FIRST', 'LAST', '8899 TAPE PARK',  
    'JACKSONVILLE', 'FLd', '34567', LV_ERROR); 

DBMS_OUTPUT.PUT_LINE(LV_ERROR); 
END; 
/

-12899 

PL/SQL procedure successfully completed. 

您可能会发现返回的错误文本,而不仅仅是数量更为有用(如果你正在返回的错误号使用数字形式参数类型),例如:

... 
EXCEPTION 
    WHEN OTHERS THEN 
    P_ERROR := SQLERRM; 
END EXAM_SP; 
/

-- same anonymous block 

ORA-12899: value too large for column "MY_SCHEMA"."BB_SHOPPER"."STATE" (actual: 3, maximum: 2) 

PL/SQL procedure successfully completed. 

当然,正如我在评论中提到,这是更好地让Oracle的异常处理只是泡沫实际的异常到调用者 - 除了也许从伐木,你应该只能真正处理你可以处理的异常。请注意,返回的错误消息不会告诉您任何有关的地方,其中代码中发生错误;如果没有异常处理程序,您将在过程中看到具有违规语句的行号。正如APC指出的那样,每个来电者都必须寻找并处理这个问题,而且很容易忽视。当然总会有例外(哈),但这似乎是做错事情的一种练习。

+0

非常感谢你提供了非常详细的答案和帮助,我知道需要花时间审查结果并给出有用的建议和建议。再次感谢你! – DKCroat

4

"If I add out parameter to procedure and I pass values I will receive this error"

亚历克斯提供了很长的答案,我只是想做一个简短的观点:这是不好的做法。大多数编程语言都包含用于处理异常的内置功能。你提出什么创造了两种架构的问题:

  1. 程序该打电话给你的程序都写不规范的代码来捕获错误,这仅仅是双方谁写的调用程序和其他人谁拥有对开发商疼痛了解他们如何工作。
  2. 您的过程不会抛出异常,即使它“失败”,它也会将成功状态返回到调用程序。如果编写调用程序的开发人员没有实现特殊代码,则异常会丢失,并且数据库可能会保持无效状态。
+0

非常感谢您的帮助和时间,我在编写程序,函数和/或pkgs方面相对较新。尽管如此,我仍然可以在这里和我的工作场所学习和选择技巧。再次感谢你 :) – DKCroat

相关问题