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.