PL/SQL変数のスコープと内部外部ブロック: ネスト構造

⚡ スマートサマリー

PL/SQLのネストされたブロックは、ブロックを別のブロックの中に配置することで、複雑なロジックを分離し、例外処理を分離することを可能にします。外側のブロックと内側のブロック間の変数スコープを理解し、ブロックラベルを使用することで、同名の変数の曖昧さを解消できます。

  • 🧱 ネストされたブロック: ネストされたブロックとは、別のブロックの実行セクションまたは例外セクション内に配置されたPL/SQLブロックのことです。
  • 🌳 外側と内側: 1つの外側のブロック(親ブロック)は、それぞれが完全なPL/SQLブロックである複数の内側のブロック(子ブロック)を含むことができます。
  • 👁️ 変数のスコープ: 外側のブロックで宣言された変数は、内側のブロック内では参照可能ですが、内側のブロックで宣言された変数は、外側からは参照できません。
  • 🏷️ ブロックラベル: 外側のブロックにラベルを付けることで、内側のブロックは、ラベル.変数名として同じ名前の外側の変数を参照できるようになります。
  • 🛡️ 例外の分離: ネストにより、各ブロックが独自の例外を処理し、ping エラー処理は、エラーを発生させたコードの近くで行う。
  • 🤖 AI 支援: GitHub CopilotなどのAIアシスタントは、ラベル付けされたネストされたブロックを作成し、変数スコープの競合を警告します。

ネストされた内部ブロックと外部ブロックにまたがるPL/SQL変数のスコープ

ネストされたブロックとは Oracle?

In PL / SQLの各ブロックは別のブロックの中に入れ子にすることができます。このようなブロックはネストされたブロックと呼ばれます。ネストされたブロックは、特定の処理を実行しながら、ping その処理のコードは別のコンテナ(ブロック)に格納されます。

ネストされたブロックの概念は、複雑なロジックを個々のブロックに分割することでプログラマーの可読性を向上させ、 例外 メインの外側ブロック内で処理される各ブロックについて。

入れ子になったブロック構造

ブロックは別のブロックの中にネストできます。実行部分または例外処理部分のどちらにもネストでき、これらのブロックにはラベルを付けることもできます。1 つの外側ブロックには、複数の内側ブロックを含めることができます。各内側ブロックはそれ自体が PL/SQLブロックつまり、内側のブロックのすべてのプロパティと特性は、外側のブロックのそれらと同じです。親ブロックはメインブロックであり、子ブロックはネストされたブロックです。

下の図は、入れ子構造のブロック構造を図示したものです。親ブロックはメインブロック、子ブロックは入れ子になったブロックです。

親となる外側のブロックと子となる内側のブロックを持つ、PL/SQLのネストされたブロックの図解。

以下に、ネストされたブロックの構文を示します。下のスクリーンショットは、ラベル付きの外側ブロックと内側ブロックを含む、ネストされたブロックの構文を示しています。

ラベル付きの外側ブロックと内側ブロック、それぞれに DECLARE、BEGIN、EXCEPTION セクションを含むネストされたブロック構文

ネストされたブロック構文

<<outer_block>>
DECLARE
 <Declarative section> 
BEGIN
 <Execution part for outer block begins>

 <<inner block>>
 DECLARE
  <Declarative section>
 BEGIN
  <Execution part for inner block>.
 EXCEPTION 
  <Exception handling part>
 END;

 <Execution part for outer block begins> 
EXCEPTION 
<Exception handling part>
END;
  • 上記の構文は、合計2つのブロックを含むネストされたブロックを示しています。
  • これらのブロックは「outer_block」と「inner_block」というラベルが付けられています。

ネストされたブロックのスコープ: 変数スコープ

ネストされたブロックでは、各ブロックを使用する前に、そのスコープと可視性を明確に理解しておく必要があります。特に内側のブロックでは、外側のブロックと内側のブロックの両方の要素が表示されるため、この点を正しく理解しておくことが重要です。

以下の項目は、ネストされたブロックで各範囲を要約したものです。

  • 外側のブロックで宣言された要素、および内側のブロックの定義前に定義された値は、内側のブロック内でも参照可能です。
  • 内側のブロックで宣言された要素は、外側のブロックからは見えません。それらは内側のブロック内でのみ表示されます。
  • 外側のブロックと内側のブロックは 変数 同じ名前で。
  • 同名の変数がある場合、デフォルトでは、内側のブロックは内側のブロック内で宣言された変数のみを参照します。
  • 内側のブロックが、内側のブロックの変数と同じ名前を持つ外側のブロックの変数を参照したい場合、外側のブロックにはラベルを付ける必要があり、外側のブロックの変数は「 。 '。

以下の例は、これらのスコープについてより深く理解するのに役立ちます。

例1: この例では、内側のブロックと外側のブロックにおける変数のスコープを確認できます。また、ブロックラベルを使用して変数を参照する方法も確認できます。

以下のスクリーンショットは例1を示しており、内側のブロックがブロックラベルを使用して外側のブロックの変数を参照しています。

ネストされたブロック内の変数スコープの例。外側のブロック変数をブロックラベルで参照している。

<<OUTER_BLOCK>>
DECLARE
var1 VARCHAR2(30):='outer_block';
var2 VARCHAR2(30):='value before inner block';
BEGIN
<<INNER_BLOCK>>
DECLARE
var1 VARCHAR2(30):='inner_block';
BEGIN
dbms_output.put_line(var1);
dbms_output.put_line(OUTER_BLOCK.var1); 
dbms_output.put_line(var2);
END;
var2:='value after inner block';
END;
/

Code 説明:

  • Code 1行目: 外側のブロックを「OUTER_BLOCK」とラベル付けします。
  • Code 3行目: 変数「var1」をVARCHAR2(30)型として宣言し、初期値を「outer_block」とします。
  • Code 4行目: 変数「var2」をVARCHAR2(30)として宣言し、初期値を「内部ブロック前の値」とします。
  • Code 6行目: 内側のブロックに「INNER_BLOCK」というラベルを付けます。
  • Code 8行目: 内部ブロックで変数「var1」をVARCHAR2(30)として宣言し、初期値を「inner_block」とします。
  • Code 10行目: 'var1' の値を表示します。ラベルが指定されていないため、デフォルトでは内部ブロックから値を取得し、'inner_block' というメッセージを表示します。
  • Code 11行目: 外側のブロック変数「var1」の値を表示します。内側のブロックにも同じ名前の変数があるため、外側のブロックのラベルを参照します。そのため、「outer_block」というメッセージが表示されます。
  • Code 12行目: 外側のブロック変数「var2」の値を表示します。内側のブロックにはこの名前の変数がないため、デフォルトでは外側のブロックから値が取得され、「内側のブロックより前の値」というメッセージが表示されます。
  • 外側のブロック内の変数「var2」には、「内側のブロック後の値」という値が割り当てられます。しかし、この割り当ては内側のブロックの定義後に行われるため、この値は内側のブロック内には存在しません。

例2: この例では、外側のブロックで宣言された数値と内側のブロックで宣言された数値の差を求めます。どちらの数値も同じ名前です。ブロックラベルがこれらの変数を参照する際にどのように役立つかを見ていきましょう。

以下のスクリーンショットは例2を示しており、同じ名前の外側ブロック変数と内側ブロック変数の差を計算しています。

ブロックラベルを使用して、同じ名前の外側ブロック変数と内側ブロック変数の差を計算する例

<<OUTER_BLOCK>>
DECLARE 
ln_val NUMBER :=5;
BEGIN
<<INNER_BLOCK>>
DECLARE 
ln_val NUMBER :=3;
BEGIN
dbms_output.put_line('The difference between outer block and inner block variable is:'||outer_block.ln_val-inner_block.ln_val);
END;
END;
/

Code 説明:

  • Code 1行目: 外側のブロックを「OUTER_BLOCK」とラベル付けします。
  • Code 3行目: 変数「ln_val」をNUMBER型で宣言し、初期値を「5」とします。
  • Code 5行目: 内側のブロックに「INNER_BLOCK」というラベルを付けます。
  • Code 7行目: 内部ブロックで変数「ln_val」をNUMBER型として宣言し、初期値を「3」とします。
  • Code 9行目: 外側のブロックと内側のブロックの「ln_val」の値の差を出力します。 。 」形式は、同じ変数名による競合を避けるために、これらの変数を参照するために使用されます。

よくあるご質問

ネストされたブロックは、別のブロックの中に配置された匿名ブロックであり、出現した場所でインラインで実行されます。 サブプログラム (プロシージャまたは関数)は、名前付きで再利用可能な単位で、別々に保存され、オプションでパラメータを指定して名前で呼び出されます。

各ブロックは独自の例外処理セクションを持つことができます。内側のブロックで発生した例外は、まずそのブロックで処理されます。処理されない例外は、外側のブロックのハンドラに伝播されます。これにより、ブロックごとにエラー処理を分離できます。

PL/SQLには小さな固定制限がないため、ブロックを何階層も深くネストすることができます。実際には、深いネストは可読性を損なうため、ほとんどのコードはネストを2~3階層に抑え、再利用可能なロジックをサブルーチンに移動させています。

ブロックラベルは、DECLAREの前に二重山括弧で囲んで名前として記述され、ブロックに名前を付けます。ラベルを使用すると、内部コードで外部変数をlabel.variable_nameのように修飾でき、GOTOのターゲットとしても機能するため、ネストされたコードを読みやすく、ドキュメント化しやすくすることができます。

はい。ネストされたブロックは、ループ内、IF分岐内、プロシージャ本体内など、実行可能なステートメントが許される場所ならどこにでも配置できます。これにより、宣言や例外処理を、それらを必要とするコード部分だけに限定することができます。

ネストは主にコンパイル時の構造化ツールであり、それ自体では実行時のオーバーヘッドはほとんど発生しません。可読性とエラー分離性を向上させます。過度に深いネストは、処理速度よりも保守性を損なう傾向があります。

Yes. GitHubコパイロット コメントから、DECLARE、BEGIN、EXCEPTIONセクションを含む、外側ブロックと内側ブロックというラベルの付いたドラフト。 Revブロックラベルと変数スコープを確認することで、同じ名前の内部変数と外部変数が意図どおりに解決されるようにします。

AIアシスタントは、ネストされたブロックを分析し、シャドウ変数、修飾されていない参照、スコープ外アクセスを検出します。この機械学習によるレビューでは、コード実行前に内部ブロックが誤って同名の変数を使用している箇所が明示されます。