0

考虑一个有 3 列的表

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

我想编写一个通用函数,它通过使用运算符验证 value1 和 value2 来返回验证结果为真或假,或者在“为空”和“非空”运算符的情况下检查 value1(最后两种情况)

4

3 回答 3

1

你可以用动态 SQL 做这样的事情(注意实际上你需要添加一堆逻辑来防止 SQL 注入攻击)

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

由于您将数据存储在表中,这意味着每列都是VARCHAR2. 不过,我的猜测是,您并不总是想使用字符串比较语义。例如,字符串 '9' 大于字符串 '11' 而数字 9 小于数字 11。如果您想使用字符串比较语义以外的其他内容,则需要添加检查参数的代码并应用您想要确定要应用的比较语义的任何逻辑,然后生成适当的动态 SQL 语句。

然而,我强烈质疑该要求是否明智。首先,从数据模型的角度来看,将数字数据存储在列中几乎没有意义VARCHAR2——当您发现自己试图在同一列中混合字符串和数字数据时,您几乎总是犯了数据模型错误。我也很难想象您要解决的业务问题会涉及这种动态功能——似乎有更好的方法来解决您要解决的任何问题。

于 2013-01-17T16:42:27.957 回答
1

在我看来,您可以在规则列表中使用展开逻辑来逃避动态 SQL。如果您需要检查一条记录,请使用类似

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
)

所以 1 = TRUE 和 0 = FALSE。

PS 如果你想支持 IN 子句,你可以使用这个解决方法(从 value2 中删除括号!)

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

SQLFiddle 上的证明

于 2013-01-18T08:50:15.083 回答
0

通过上面的问题和结果,我想出了一些我们应该注意使用字符串和比较的点:

-----> 可以将数值与任何比较函数进行比较,即;

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

但要小心使用引号;

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

因为,这里的隐式位置比较是通过检查9>1(12 中的 1)来完成的,所以条件 9>1 为真,所以结果为 Y。

与数字进行比较的正确方法是不带引号:

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

----->用'>'和'<'将一个字符串与另一个字符串进行比较是没有意义的

-----> 我们UTL_MATCH专门为字符串匹配打包。

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.
于 2013-01-23T04:48:26.150 回答