0

3列のテーブルを考えてみましょう

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

演算子を使用して value1 を value2 で検証するか、「is null」および「is not null」演算子の場合は value1 をチェックすることによって、検証結果を true または false のいずれかで返すジェネリック関数を作成したい (最後の 2 つのケース)

4

3 に答える 3

1

ルールのリストで巻き戻しロジックを使用して動的 SQL をエスケープできるように思えます。1 つのレコードを確認する必要がある場合は、次のようなものを使用します

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句をサポートしたい場合は、この回避策を使用できます(値2から括弧を削除してください!)

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

SQLFiddle での証明

于 2013-01-18T08:50:15.083 に答える
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. ただし、文字列比較セマンティクスを常に使用したいとは限りません。For example, the string '9' is greater than the string '11' while the number 9 is less than the number 11. 文字列比較セマンティクス以外のものを使用する場合は、パラメーターを検査するコードを追加する必要があります。適用する比較セマンティクスを決定するために任意のロジックを適用し、適切な動的 SQL ステートメントを生成します。

ただし、要件の賢明さには強く疑問を呈します。まず、データ モデルの観点からは、数値データを列に格納することはほとんど意味がありVARCHAR2ません。同じ列に文字列データと数値データを混在させようとすると、ほとんどの場合、データ モデルの間違いを犯してしまいます。また、あなたが解決しようとしているビジネス上の問題に、この種の動的機能が関係しているとは想像もつきません。解決しようとしている問題が何であれ、それを解決するためのより良い方法があるようです。

于 2013-01-17T16:42:27.957 に答える
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 に答える