简体   繁体   中英

Oracle: Expression is of Wrong Type using multiple variables

I'm trying to make a modification to an existing PL/SQL package I coded some time ago. The original block in question looked like this (which worked fine)

FUNCTION GEN_COLUMN_TYPE ( DTYPE IN VARCHAR2,  --DATATYPE OF THE COLUMN
                            PRCISION IN NUMBER, --PRECISION OF THE COLUMN
                            SCLE IN NUMBER,    --PRECISION OF THE COLUMN
                            DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
                            CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
                            APP_CODE IN VARCHAR2     -- DATABASE TYPE
                            )RETURN STRING IS

  V_COLUMNTYPE  STRING(40) := NULL;
  BEGIN
             V_COLUMNTYPE := DTYPE;
             BEGIN
              SELECT TARGET_DATATYPE  INTO V_COLUMNTYPE  FROM DDL_DATATYPE_MAP  DDM
              INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND DDM.SOURCE_DBMS=DSA.SOURCE_DBMS
              AND  DSA.APPLICATION_CODE=APP_CODE
              WHERE DDM.SOURCE_DATATYPE=DTYPE;
             END;

I have modified it now to look like this. The only change I made was adding the 2 new variables into the definition and the "SELECT INTO" statement so I could use them based on the same join criteria later in the code.

FUNCTION GEN_COLUMN_TYPE ( DTYPE IN VARCHAR2,  --DATATYPE OF THE COLUMN
                            PRCISION IN NUMBER, --PRECISION OF THE COLUMN
                            SCLE IN NUMBER,    --PRECISION OF THE COLUMN
                            DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
                            CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
                            APP_CODE IN VARCHAR2,     --APPLICATION CODE
                            DBMS_TYPE VARCHAR2,    --DATABASE TYPE
                            VAR_LENGTH_IND VARCHAR2  --WHETHER THE FIELD NEEDS PARENS OR NOT
                            )RETURN STRING IS

  V_COLUMNTYPE  VARCHAR2(40) := NULL;
  BEGIN
             V_COLUMNTYPE := DTYPE;

              BEGIN
              SELECT TARGET_DATATYPE, SOURCE_DBMS, TARGET_VARIABLE_LEN_IND  INTO V_COLUMNTYPE, DBMS_TYPE, VAR_LENGTH_IND FROM DDL_DATATYPE_MAP  DDM
              INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND DDM.SOURCE_DBMS=DSA.SOURCE_DBMS
              AND  DSA.APPLICATION_CODE=APP_CODE
              WHERE DDM.SOURCE_DATATYPE=DTYPE;
             END;

And I'm getting the all-too-common "PL-00382: expression is of wrong type" on the "SELECT ... INTO" statement at the end. All three variables and columns datatypes are varchar2. I've poured over this and can't see anything wrong. What am I missing?

Edit: Sharing this attempt to use local variables and rewrote the naming for more readability. However I am getting an error on "'V_DBMS_TYPE' must be declared"

FUNCTION GEN_COLUMN_TYPE ( P_DTYPE IN VARCHAR2,  --DATATYPE OF THE COLUMN
                            P_PRCISION IN NUMBER, --PRECISION OF THE COLUMN
                            P_SCLE IN NUMBER,    --PRECISION OF THE COLUMN
                            P_DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
                            P_CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
                            P_APP_CODE IN VARCHAR2
                            )RETURN STRING IS

  V_COLUMNTYPE  VARCHAR2(40) := NULL;
  BEGIN
             V_COLUMNTYPE := P_DTYPE;
             DECLARE
             V_DBMS_TYPE VARCHAR2(30) := NULL;    --DATABASE TYPE
             V_VAR_LENGTH_IND VARCHAR2(30) := NULL;  --WHETHER THE FIELD NEEDS PARENS OR NOT
              BEGIN
              SELECT TARGET_DATATYPE, SOURCE_DBMS, TARGET_VARIABLE_LEN_IND  INTO V_COLUMNTYPE, V_DBMS_TYPE, V_VAR_LENGTH_IND FROM DDL_DATATYPE_MAP  DDM
              INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND DDM.SOURCE_DBMS=DSA.SOURCE_DBMS
              AND  DSA.APPLICATION_CODE=P_APP_CODE
              WHERE DDM.SOURCE_DATATYPE=P_DTYPE;

You added two parameters to your function. You don't specify a parameter mode ( IN , OUT , or IN OUT ) so the default is IN . An IN parameter cannot be the target of a SELECT INTO because the parameter is read-only inside the function.

It is not clear to me whether you really wanted to declare two new local variables, rather than two additional parameters, or whether you really want to declare the two new parameters to be OUT or IN OUT parameters. If you declare the parameters as OUT or IN OUT , they could be the target of an assignment. But your function would no longer be callable from SQL. If you declare two new local variables, the function would still be callable from SQL but you would not be able to pass in (or be passed back) the values that you gather from your SELECT statement.

As a general suggestion, I would much prefer to see a common naming convention used to differentiate parameters from local variables and from column names-- that makes reading the code much easier. If your parameters, for example, used a standard P_ prefix, it would be immediately clear in your SELECT statement that some of your targets were local variables and some were parameters.

Based on the comments, you want to declare additional local variables rather than adding parameters. That would look something like

CREATE OR REPLACE FUNCTION GEN_COLUMN_TYPE ( 
                           DTYPE IN VARCHAR2,  --DATATYPE OF THE COLUMN
                           PRCISION IN NUMBER, --PRECISION OF THE COLUMN
                           SCLE IN NUMBER,    --PRECISION OF THE COLUMN
                           DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
                           CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
                           APP_CODE IN VARCHAR2     --APPLICATION CODE
                         )
  RETURN VARCHAR2
IS
  V_DBMS_TYPE      VARCHAR2(100);    --DATABASE TYPE
  V_VAR_LENGTH_IND VARCHAR2(100);  --WHETHER THE FIELD NEEDS PARENS OR NOT
  V_COLUMNTYPE     VARCHAR2(40) := NULL;
BEGIN
  V_COLUMNTYPE := DTYPE;

  SELECT TARGET_DATATYPE, SOURCE_DBMS, TARGET_VARIABLE_LEN_IND  
    INTO V_COLUMNTYPE, V_DBMS_TYPE, V_VAR_LENGTH_IND 
    FROM DDL_DATATYPE_MAP  DDM
         INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND  
                                                  DDM.SOURCE_DBMS=DSA.SOURCE_DBMS AND
                                                  DSA.APPLICATION_CODE=APP_CODE
   WHERE DDM.SOURCE_DATATYPE=DTYPE;

  <<more code>>
END;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM