私たちのシステムの 1 つで SP の保守性を改善しようとしているときに、値の配列 (この場合はテーブル名) をハードコードするよりもループを使用する方がよいと判断し、それに応じてコードをリファクタリングしようとしました。またはシステムからテーブルを削除しても、配列を編集する必要はありませんでした。今のところ、ループの理由と理由を脇に置いて (私はそれらに対する議論をよく知っています)、誰かが何が起こっているのか説明できますか?
同じデータベースに SourceUser と DestUser という 2 人のユーザーがいて、それぞれのテーブルが同じテーブルスペースにあるとします。SourceUser の一連のストアド プロシージャは、レポート目的で SourceUser から DestUser にデータを取り込みます。この一環として、実行される最初のプロシージャは、DestUser 内のすべてのテーブルを削除し、それらを再作成します。繰り返しますが、ここでそれを行うことの相対的なメリットについては議論しません。
SourceUser には、DestUser に対する Drop Any Table 権限と Create Any Table 権限があります。DestUser には保持したいテーブルが 1 つあります。したがって、手順で作成した SQL は次のようになります。
Begin
For T In (SELECT TABLE_NAME FROM all_tables WHERE TABLE_NAME != 'MIDBLOG' AND OWNER = sTarget_DB) Loop
Begin
Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME);
Exception
When Others Then
--Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place.
NULL;
End;
End Loop;
End;
この場合、sTarget_DB は DestUser に設定され、このコードは SourceUser に対して実行されています。
手順を実行すると、テーブルが削除されていないことがわかります (開始前に、MIDBLOG という名前のテーブルを含む数十のテーブルがあることを確認しました)。私はそれをSQL Developerデバッグモードで実行しましたが、処理する行がないと思われるため、実行はループの内側に到達することさえありませんが、selectステートメントが数十のテーブル名を返すことは確かです.
次に、これを次のように修正しました。
Begin
For T In (SELECT TABLE_NAME FROM all_tables WHERE OWNER = sTarget_DB) Loop
Begin
If T.TABLE_NAME != 'MIDBLOG' THEN
Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME);
End If;
Exception
When Others Then
--Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place.
NULL;
End;
End Loop;
End;
これを実行した後、削除された唯一のテーブルは、私が削除したくないものでした! さらに奇妙なのは、select クエリが 1 行だけを返すかのように、ループが 1 回しか実行されなかったことです。SQL Developer 3.2 でデバッグ中にプロシージャを実行すると、この問題が発生することがわかりました。SQL Developer (おそらく 3.1) 上の同僚の PC で同じことを行いましたが、ループは 1 回だけ実行されましたが、今回はテーブル MIDBLOG を削除しないことを正しく決定し、他のすべてをそのままにしました。
上記の例のいずれかを SQL Developer で無名ブロックとして実行すると、期待どおりの動作をします。より冗長な明示カーソル宣言を試してみたところ、以前と同じ結果になりました。例外は一度もありませんでした。
これはすべて、Oracle 10g Enterprise Edition リリース 10.2.0.4.0 (64 ビット) にありました。Oracle 11g Enterprise Edition Release 11.2.0.1.0 (64bit) で試してみると、問題なく動作しました。いったいなぜ、このような基本的な要件が、2 つのバージョン間でこれほど大きく異なる動作を示すのでしょうか? 同じビットのコードを使用して、両方のバージョンで思い通りに動作することはできますか?