How to get column name for which PL/SQL object population is failing

天大地大妈咪最大 提交于 2021-02-07 09:15:19

问题


I have PL/SQL table-type and procedure as below. It is just part of code. While populating PL/SQL table type variable I am getting exception.

CREATE OR REPLACE TYPE OBJ_EMPLOYEE AS OBJECT
(
     EMPID               NUMBER(12)     ,     
     EMPLOYEENAME        VARCHAR2(100)  ,
     /* more attributes */
     STATUS              VARCHAR2(20)   ,
     UPDTDATE            DATE           ,
);

CREATE OR REPLACE TYPE TAB_EMPLOYEE IS TABLE OF OBJ_EMPLOYEE;

CREATE OR REPLACE PROCEDURE sp_getEmpDetails
(
     p_ErrorCode_o       OUT VARCHAR2,
     p_ErrorMsg_o        OUT VARCHAR2
)
IS    
     TEMP_EMPLOYEE    TAB_EMPLOYEE := TAB_EMPLOYEE();    
BEGIN

     /* Some code */

     BEGIN

          SELECT OBJ_EMPLOYE
          (
               EMPID          ,
               EMPLOYEENAME   ,
               /* more attributes */
               STATUS         ,
               UPDTDATE
          )
          BULK COLLECT INTO TEMP_EMPLOYEE
          FROM (
          SELECT    EMPID,
                    EMPLOYEENAME,
                    /* more attributes */
                    STATUS,
                    SYSDATE AS UPDTDATE
          FROM      TEST_TABLE
          );

     EXCEPTION
          WHEN OTHERS THEN
               p_vcErrorCode_o :=  SQLCODE;
               p_vcErrorMsg_o := 'Fail 1' || SQLERRM;

     END;

     /* Some code */

EXCEPTION
     WHEN OTHERS THEN
          p_vcErrorCode_o :=  SQLCODE;
          p_vcErrorMsg_o := SQLERRM;
END sp_getEmpDetails;
/

I am getting exception - "ORA-22814: attribute or element value is larger than specified in type". After checking length and data of each and every column, I found that TEST_TABLE.EMPLOYEENAME value is more than 100 chars. Is there a way to print column name for which object population is failing?

Thanks in advance for help


回答1:


You can get a more meaningful error message by creating a custom constructor.

Objects already come with a default constructor that accepts every value and simply assigns them. You can recreate that default constructor with PL/SQL. Then the errors happen in your custom PL/SQL code and the line numbers will be more meaningful.

The code is relatively simple and only affects the type and the type body. None of the code that uses the objects has to change.

For example:

CREATE OR REPLACE TYPE OBJ_EMPLOYEE AS OBJECT
(
     EMPID               NUMBER(12)     ,     
     EMPLOYEENAME        VARCHAR2(100)  ,
     /* more attributes */
     STATUS              VARCHAR2(20)   ,
     UPDTDATE            DATE           ,
     CONSTRUCTOR FUNCTION OBJ_EMPLOYEE
          (EMPID NUMBER, EMPLOYEENAME VARCHAR2, STATUS VARCHAR2, UPDTDATE DATE)
          RETURN SELF AS RESULT
);


CREATE OR REPLACE TYPE BODY OBJ_EMPLOYEE AS
     --Recreate default constructor to generate more useful error message.
     CONSTRUCTOR FUNCTION OBJ_EMPLOYEE
          (EMPID NUMBER, EMPLOYEENAME VARCHAR2, STATUS VARCHAR2, UPDTDATE DATE)
          RETURN SELF AS RESULT AS
     BEGIN
          SELF.EMPID := empid;
          SELF.EMPLOYEENAME := employeename;
          SELF.STATUS := status;
          SELF.UPDTDATE := updtdate;
          RETURN;
     END;
END;
/

Now the program should generate an error message like below.

ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "JHELLER.OBJ_EMPLOYEE", line 8
ORA-06512: at line 17

View program sources of error stack?

The error is more obvious now because line 8 is SELF.EMPLOYEENAME := employeename;.




回答2:


You can if you loop through the rows one-by-one and check each value as you insert it into the object:

SQL Fiddle

Oracle 11g R2 Schema Setup:

CREATE TABLE TEST_TABLE ( EMPID, EMPLOYEENAME, STATUS ) AS
SELECT 1, 'A',                   'X' FROM DUAL UNION ALL
SELECT 2, RPAD( 'B', 101, 'B' ), 'Y' FROM DUAL UNION ALL
SELECT 3, 'C',                   'Z' FROM DUAL
/


CREATE OR REPLACE TYPE OBJ_EMPLOYEE AS OBJECT
(
     EMPID               NUMBER(12)     ,     
     EMPLOYEENAME        VARCHAR2(100)  ,
     STATUS              VARCHAR2(20)   ,
     UPDTDATE            DATE
)
/

CREATE OR REPLACE TYPE TAB_EMPLOYEE IS TABLE OF OBJ_EMPLOYEE
/


CREATE OR REPLACE PROCEDURE sp_getEmpDetails
(
  p_vcErrorCode_o       OUT VARCHAR2,
  p_vcErrorMsg_o        OUT VARCHAR2
)
IS
  TEMP_EMPLOYEE    OBJ_EMPLOYEE;
  TEMP_EMPLOYEES   TAB_EMPLOYEE := TAB_EMPLOYEE();    
BEGIN
  FOR rec IN ( SELECT * FROM TEST_TABLE ) LOOP
    TEMP_EMPLOYEE := OBJ_EMPLOYEE( NULL, NULL, NULL, SYSDATE );
    BEGIN
      TEMP_EMPLOYEE.EMPID := rec.EMPID;
    EXCEPTION
      WHEN OTHERS THEN
        p_vcErrorCode_o :=  SQLCODE;
        p_vcErrorMsg_o := 'Fail on EMPID: ' || SQLERRM;
    END;

    BEGIN
      TEMP_EMPLOYEE.EMPLOYEENAME := rec.EMPLOYEENAME;
    EXCEPTION
      WHEN OTHERS THEN
        p_vcErrorCode_o :=  SQLCODE;
        p_vcErrorMsg_o := 'Fail on EMPLOYEENAME: ' || SQLERRM;
    END;

    BEGIN
      TEMP_EMPLOYEE.STATUS := rec.STATUS;
    EXCEPTION
      WHEN OTHERS THEN
        p_vcErrorCode_o :=  SQLCODE;
        p_vcErrorMsg_o := 'Fail on STATUS: ' || SQLERRM;
    END;

    TEMP_EMPLOYEES.EXTEND();
    TEMP_EMPLOYEES( TEMP_EMPLOYEES.COUNT ) := TEMP_EMPLOYEE;
  END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    p_vcErrorCode_o :=  SQLCODE;
    p_vcErrorMsg_o := 'Fail 1' || SQLERRM;
END sp_getEmpDetails;
/

Query 1:

DECLARE
  code NUMBER(6,0);
  errm VARCHAR2(4000);
BEGIN
  sp_getEmpDetails( code, errm );
  DBMS_OUTPUT.PUT_LINE( code || ' - ' || errm );
END;

Results:

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



回答3:


Just look at your TEST_TABLE table for the value that is too long:

SELECT tt.employeename
FROM test_table tt
WHERE LENGTH( tt.employeename ) > 100

A better solution would be to make the employeename inside your obj_employee object the same length as the table, so this doesn't happen in the first place. (I can't remember if you can use the %TYPE operator in an object definition.)



来源:https://stackoverflow.com/questions/49109464/how-to-get-column-name-for-which-pl-sql-object-population-is-failing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!