1

I have the following code, where I am trying to pass IF statement condition dynamically:

DECLARE
v_flag            NUMBER(2);
v_if_statement VARCHAR2(500);
v_sql_statement VARCHAR2(500);
v_criteria        VARCHAR2(150);
v_condition VARCHAR2(30) := '%sales% > 300';
BEGIN
v_criteria := REPLACE(v_condition , '%sales%' , 500.32);

      v_if_statement := 'IF :'||v_criteria||' '||
          'THEN :v_flag := 1;'||' '||
      'ELSE :v_flag := 0;'||' '||
          'END IF;';

v_sql_statement := 'BEGIN '||v_if_statement||' END;';         


      EXECUTE IMMEDIATE v_sql_statement USING IN v_criteria, OUT v_flag;
       dbms_output.put_line('The output is : '||v_flag);

 END;

I get the following error: ORA-06502: PL/SQL: numeric or value error: character to number conversion error

Any help would be appreciated !

Thanks..

1
  • 1
    After building variable v_sql_statement, before executing it, print it out to see the full picture - then you can easily identify the problem. Commented Jul 11, 2018 at 6:50

2 Answers 2

2

If you print out your final generated statement as @Ychdziu suggested, you'll see it ends up as:

BEGIN IF :500.32 > 300 THEN :v_flag := 1; ELSE :v_flag := 0; END IF; END;

which isn't what you wanted. You either need to supply the value to be checked (500.32) as a bind variable as shown in @Ychdziu's answer, or concatenate the condition into the statement without trying to make that another bind variable:

DECLARE
  v_flag          NUMBER(2);
  v_if_statement  VARCHAR2(500);
  v_sql_statement VARCHAR2(500);
  v_criteria      VARCHAR2(150);
  v_condition     VARCHAR2(30) := '%sales% > 300';
BEGIN
  v_criteria := REPLACE(v_condition , '%sales%' , 500.32);

  v_if_statement := 'IF '||v_criteria||' '||
    'THEN :v_flag := 1;'||' '||
    'ELSE :v_flag := 0;'||' '||
    'END IF;';

  v_sql_statement := 'BEGIN '||v_if_statement||' END;';         
  dbms_output.put_line('statament: '||v_sql_statement);

  EXECUTE IMMEDIATE v_sql_statement USING OUT v_flag;
  dbms_output.put_line('The output is : '||v_flag);

 END;
/

The generated statement is now

BEGIN IF 500.32 > 300 THEN :v_flag := 1; ELSE :v_flag := 0; END IF; END;

so there is only one bind variable.

But it's usually better to bind the variable if you can. In your example code the entire condition seems to be a variable (I assume this is just an exercise, but it could be passed in or come from a table), so you could combine both and replace the %sales% placeholder with a bind variable reference instead:

DECLARE
  v_flag          NUMBER(2);
  v_if_statement  VARCHAR2(500);
  v_sql_statement VARCHAR2(500);
  v_criteria      VARCHAR2(150);
  v_condition     VARCHAR2(30) := '%sales% > 300';
BEGIN
  v_criteria := REPLACE(v_condition , '%sales%' , ':v_value');

  v_if_statement := 'IF '||v_criteria||' '||
    'THEN :v_flag := 1;'||' '||
    'ELSE :v_flag := 0;'||' '||
    'END IF;';

  v_sql_statement := 'BEGIN '||v_if_statement||' END;';         
  dbms_output.put_line('statament: '||v_sql_statement);

  EXECUTE IMMEDIATE v_sql_statement USING IN 500.32, OUT v_flag;
  dbms_output.put_line('The output is : '||v_flag);

 END;
/

Not the generated statement is:

BEGIN IF :v_value > 300 THEN :v_flag := 1; ELSE :v_flag := 0; END IF; END;

and you can pass the actual value you want to check, 500.32, directly via the USING clause - either as a literal as I've done here, or with a separate numeric variable.

Sign up to request clarification or add additional context in comments.

Comments

1

There are several problems with this query: 1) The SQL statement itself is in bad structure; 2) DB tries to convert v_criteria to number type, but the v_criteria is '500.32 > 300' - you can't convert like that. Try this way:

DECLARE
  v_flag            NUMBER(2);
  v_if_statement VARCHAR2(500);
  v_sql_statement VARCHAR2(500);
  v_criteria        VARCHAR2(150);
BEGIN
  v_criteria := 300.32;

  v_if_statement := q'[IF :v_criteria > 300
      THEN :v_flag := 1;
  ELSE :v_flag := 0;
      END IF;]';

  v_sql_statement := 'BEGIN '||v_if_statement||' END;';         
  dbms_output.put_line('v_sql_statement is : '||v_sql_statement);


  EXECUTE IMMEDIATE v_sql_statement USING IN v_criteria, OUT v_flag;
  dbms_output.put_line('The output is : '||v_flag);

END; 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.