puneet
puneet

Reputation: 89

oracle dynamic validation

Consider a table with 3 columns

Value1   operator     value2
abc          =               xyz
1            !=               2
5            >                8
9            <=              11
xyz          is not Null
{null val}   is null

I want to write a genric function which returns the validated result either true or false by validating value1 with value2 using the operator or check value1 in case of 'is null' and 'is not null' operators (Last two cases)

Upvotes: 0

Views: 579

Answers (3)

ajmalmhd04
ajmalmhd04

Reputation: 2602

looking through above question and the results, i came up with some points that we should take care of using string and comparisons:

-----> its possible to compare numeric values with any comparison function ,ie;

=, !=, <, >, <=, >=, IS NULL, LIKE, BETWEEN, IN

but beware of using quotes;

SELECT (CASE WHEN '9' > '12' THEN 'Y' ELSE 'N' END) FROM dual;-- results Y

because, here the implicit positional comparison is done by checking 9>1 (1 in the 12), so the condition 9>1 is true, so results as Y.

The correct way of comparison with numeric is without quotes:

SELECT (CASE WHEN 9 > 12 THEN 'Y' ELSE 'N' END) FROM dual;--results N

-----> its meaningless to compare a string with another with '>' and '<'

-----> we've UTL_MATCH package especially for string matching.

SELECT utl_match.edit_distance( 'abc','abcde' ) FROM dual;--results 2, shows no:of edits required to make string1 to string2.
SELECT UTL_MATCH.EDIT_DISTANCE_similarity('abc', 'abcde') FROM DUAL;-- results 60, shows the similarity percentage of two strings.

Upvotes: 0

knagaev
knagaev

Reputation: 2957

It seems to me you can escape dynamic SQL with unwinding logic in a list of rules. If you need to check one record use something like

with CheckedTable as (select * from t where primary_key = ID)
select count(*) from 
(
select * from CheckedTable where operator = '=' and value1 = value2
union all
select * from CheckedTable where operator = '!=' and value1 <> value2
union all
select * from CheckedTable where operator = '>' and value1 > value2
union all
...
select * from CheckedTable where operator = 'is null' and value1 is null
)

So 1 = TRUE and 0 = FALSE.

P.S. If you want to support IN clause you can use this workaround (remove brackets from value2!)

select * from CheckedTable where operator = 'in' and ',' || value2 || ',' like '%,' || value1 || ',%'

proof on SQLFiddle

Upvotes: 1

Justin Cave
Justin Cave

Reputation: 231661

You could do something like this with dynamic SQL (note that in reality you'd need to add a bunch of logic to prevent SQL injection attacks)

SQL> ed
Wrote file afiedt.buf

  1  create or replace function evaluate( p_val1 in varchar2,
  2                                       p_op   in varchar2,
  3                                       p_val2 in varchar2 )
  4    return varchar2
  5  is
  6    l_result varchar2(1);
  7    l_sql_stmt varchar2(1000);
  8  begin
  9    if( p_val2 is not null )
 10    then
 11      l_sql_stmt := 'select (case when :1 ' || p_op || ' :2 then ''Y'' else ''N'' end) from dual';
 12      execute immediate l_sql_stmt
 13         into l_result
 14        using p_val1, p_val2;
 15    else
 16      l_sql_stmt := 'select (case when :1 ' || p_op || ' then ''Y'' else ''N'' end) from dual';
 17      execute immediate l_sql_stmt
 18         into l_result
 19        using p_val1;
 20    end if;
 21    return l_result;
 22* end;
SQL> /

Function created.

SQL>  select evaluate( 'xyz', 'is not null', null )
  2     from dual;

EVALUATE('XYZ','ISNOTNULL',NULL)
--------------------------------------------------------------------------------
Y

SQL> select evaluate( 'abc', '=', 'xyz' )
  2    from dual;

EVALUATE('ABC','=','XYZ')
--------------------------------------------------------------------------------
N

Since you are storing the data in a table, that implies that each column is a VARCHAR2. My guess, though, is that you don't always want to use string comparison semantics. For example, the string '9' is greater than the string '11' while the number 9 is less than the number 11. If you want to use something other than string comparison semantics, you'd need to add code that inspected the parameters and applied whatever logic you would like to determine what comparison semantics you want to apply and then generated the appropriate dynamic SQL statement.

I would strongly question the wisdom of the requirement, however. First off, it makes little sense from a data model standpoint to store numeric data in a VARCHAR2 column-- when you find yourself trying to mix string and numeric data in the same column, you've almost always made a data model mistake. I would also be hard-pressed to imagine what business problem you are trying to solve that would involve this sort of dynamic function-- it seems likely that there is a better way to solve whatever problem you are attempting to solve.

Upvotes: 1

Related Questions