PostgreSQLからRETURNING *の動作をエミュレートするDML文の影響を受ける行をフェッチするOracle関数(8i用)を作成しました。典型的な関数呼び出しは次のようになります。pl/sqlブロックのsubselects上のOracle 8i動的SQLエラー
SELECT tablename_dml('UPDATE tablename SET foo = ''bar''') FROM dual;
機能を各テーブルに対して自動的に作成し、引数として渡されたクエリを実行するために、動的SQLを使用しています。また、動的にも... BEGIN ENDブロック内にラップされたクエリ実行の文:
EXECUTE IMMEDIATE 'BEGIN'||query||' RETURNING col1, col2 BULK COLLECT INTO :1, :2;END;' USING OUT col1_t, col2_t;
このperculiar建設の背後にある理由は、DMLから値を取得するための唯一の方法であると思われることです複数の行に影響するステートメント。 col1_tとcol2_tは両方とも、テーブルの列に対応する型のコレクションとして宣言されています。
最後に、問題に。渡された照会に副選択が含まれていると、その関数を実行すると構文エラーが発生します。以下これを説明するためのsimpe例である:
CREATE TABLE xy(id number, name varchar2(80));
CREATE OR REPLACE FUNCTION xy_fn(query VARCHAR2) RETURN NUMBER IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'BEGIN '||query||'; END;';
ROLLBACK;
RETURN 5;
END;
SELECT xy_fn('update xy set id = id + (SELECT min(id) FROM xy)') FROM DUAL;
最後の文は、次のエラーを生成します(SELECT分(ID)がある記載されているSELECT)
ORA-06550: line 1, column 32: PLS-00103: Encountered the symbol "SELECT" when expecting one of the following: (- + mod not null others avg count current exists max min prior sql stddev sum variance execute forall time timestamp interval date
この問題がで発生8i(8.1.6)ではなく、10gである。 BEGIN .. ENDブロックが削除された場合、問題は消えます。 照会の副選択が他の何か、すなわち定数で置き換えられた場合、問題は消えます。
残念ながら、私は8iで止まってBEGINを削除しています.. ENDはオプションではありません(上記の説明を参照)。
ここには特定のOracle 8iの制限事項がありますか?それは動的SQLでそれを克服することは可能ですか?
8i ??拡張サポートは5年以上前に終了しました... – Ben
@Ben:笑うことができますが、私はまだ8iデータベースインスタンスに変更を加えています... –
@JeffreyKemp、私は笑っていません!時には移動するのが難しいこともあることを理解しています(まだ接続されている9iボックスがいくつかありますが、アップグレードしています)。可能な限りサポートされているバージョンを実際に使用する必要がある場合は、サポートされていないバージョンを使用するよりも理にかなっています。 – Ben