多くのクエリを実行し、変数に格納する多くの値を取得するストアド プロシージャがあります。この手順で、ユーザーが指定したテーブルにクエリ結果を挿入できるようにしたいと考えています。指定されたテーブル名を varchar パラメータとして保存しますが、このテーブルに挿入するにはどうすればよいですか?
コンパイル時に、Oracle はテーブルが存在しないと言っています。
おそらく、使用している変数の名前を持つテーブルが存在しないことを示していますが、もちろん存在しません。実際のテーブルは、コンパイル時に存在する場合と存在しない場合があります。柔軟であるため、そうではない可能性があると想定する方がおそらく安全です。いずれにせよ、それがどうなるかわからないので、これを実現するには動的 SQL を使用する必要があります。
別の回答のコメントで述べたように、SQL インジェクションに注意する必要があります。通常、動的 SQL でバインド変数を使用したいのですが、オブジェクト名にバインドを使用できないため、連結する必要があります。dbms_assert
パッケージを含む 11g を使用していることを願っています。
簡単な例を次に示します。
create or replace procedure p42 (table_name varchar2) as
begin
execute immediate 'insert into '
|| dbms_assert.qualified_sql_name(table_name)
|| ' select * from dual';
end;
/
次に、プロシージャが既に存在する後にテーブルを作成し、プロシージャを正常に呼び出すことができます。
create table t42 (dummy varchar2(1));
exec p42('t42');
select * from t42;
DUMMY
-----
X
実際のクエリは明らかにより複雑になり、ターゲット テーブル名と共に渡すフィルター値にはバインド変数を使用する必要があります。
この呼び出しの利点は、dbms_assert
不正なものが渡された場合や、厄介なものが渡された場合にエラーが発生することです。
exec p42('t42 select ''Y'' from dual union all');
ORA-44004: invalid qualified SQL name
ORA-06512: at "SYS.DBMS_ASSERT", line 207
ORA-06512: at "STACKOVERFLOW.P42", line 3
ORA-06512: at line 1
プロシージャが渡された値を単純に連結した場合:
execute immediate 'insert into ' || table_name || ' select * from dual';
...次に、同じ呼び出しで 2 つの行がテーブルに挿入されます。
exec p42('t42 select ''Y'' from dual union all');
select * from t42;
DUMMY
-----
Y
X
データの整合性が重要である場合、これは心配する必要があります。使用できない場合はdbms_assert
、渡された名前が実際に存在し、aなどのall_tables
ようなものが含まれていないことを確認してみてください。 union
-in関数はあなたのために大変な仕事をします。
次のようなことを試してください:
exec ('insert into ' + @tblname + ' (col) values (123)')