これは非常に特殊な要件のようであり、堅牢な方法で解決するのは難しいでしょう。 STMT_OR_VALUEは、One ColumnTwoUsagesアンチパターンの実施形態です。さらに、STMT_OR_VALUEを解決するには、フロー制御ロジックと動的SQLの使用が必要です。したがって、純粋なSQLソリューションにすることはできません。動的クエリをアセンブルして実行するには、PL/SQLを使用する必要があります。
これがソリューションの概念実証です。 SQLから呼び出すことができる関数を選択しました。これは、1つの仮定に依存します。TEST1.STMT_OR_VALUEに挿入するすべてのクエリ文字列には、単一の数値列の射影があります。 すべての値の文字列は数値データのみのCSVです 。この条件を使用すると、動的クエリを実行するか、文字列を一連の数値にトークン化する関数を簡単に作成できます。どちらもネストされたテーブルにまとめて収集されます:
create or replace function get_ids (p_name in test1.name%type)
return sys.odcinumberlist
is
l_rec test1%rowtype;
return_value sys.odcinumberlist;
begin
select * into l_rec
from test1
where name = p_name;
if l_rec.type = 'SQL_QUERY' then
-- execute a query
execute immediate l_rec.stmt_or_value
bulk collect into return_value;
else
-- tokenize a string
select xmltab.tkn
bulk collect into return_value
from ( select l_rec.stmt_or_value from dual) t
, xmltable( 'for $text in ora:tokenize($in, ",") return $text'
passing stmt_or_value as "in"
columns tkn number path '.'
) xmltab;
end if;
return return_value;
end;
/
動的SQLステートメントを実行する方法は複数あり、CSVを一連の数値にトークン化する方法は複数あることに注意してください。私の決定は恣意的です:ここであなたの好みの方法を自由に置き換えてください。
この関数は、table()
を使用して呼び出すことができます 電話:
select *
from data
where id in ( select * from table(get_ids('first'))) -- execute query
or id in ( select * from table(get_ids('second'))) -- get string of values
/
このアプローチの大きな利点は、STMT_OR_VALUEの評価に関するロジックをカプセル化し、動的SQLの使用を隠すことです。したがって、読みやすさを維持しながらSQLステートメントで使用したり、IDのセットを生成するためのメカニズムをさらに追加したりするのは簡単です。
ただし、このソリューションは脆弱です。 test1
の値が テーブルはルールに従います。つまり、それらは単一の数値のストリームに変換可能である必要があるだけでなく、SQLステートメントはEXECUTEIMMEDIATEによって有効で実行可能である必要があります。たとえば、質問のサンプルデータの末尾のセミコロンは無効であり、EXECUTEIMMEDIATEがスローされます。動的SQLは、コンパイルエラーをランタイムエラーに変換するため、特に困難です。