PL/SQL Nested Blocks

Many developers are familiar with (or at least aware of) try-catch blocks in their codes. These help to isolate parts of codes inside the main program.  Oracle provides a similar mechanism to isolate or break down the code into multiple pieces; it is called NESTED BLOCKS.

You are probably already familiar with the anonymous and named blocks (if you are not, please check the Introduction to PL/SQL). Not only you can define blocks of codes but you can also define blocks inside blocks, and that is exactly what nested blocks are.

Why would you do that? Well, the answer is pretty simple: isolation, improved readability, and individual exception handling without the need to close the whole program.

What are Nested blocks?

Nested blocks are, as mentioned above, blocks inside another block. Each block (even nested blocks) can have its own DECLARE and EXCEPTION section.
oracle_world_plsql_nested_blocks

There is one trick with the variables inside each block. For the parent block, it applies that all variables are accessible from the nested block but not the other way around.

DECLARE
  v_blockName VARCHAR2(50);
BEGIN
  v_blockName := 'Parent block';
  
  -- nested block
  DECLARE
    v_nestedBlockName VARCHAR2(50);
  BEGIN
    v_nestedBlockName := 'Nested block';

    dbms_output.put_line(v_blockName);
    dbms_output.put_line(v_nestedBlockName); 
  END;
  -- end of nested block

  dbms_output.put_line(v_blockName);
  dbms_output.put_line(v_nestedBlockName); -- will throw an error: PLS-00201

END;

You can as well use a variable inside the nested block with the same name as in the parent block but if you want to keep it separated, you have to re-DECLARE it in the nested block.

DECLARE
  v_blockName VARCHAR2(50);
BEGIN
  v_blockName := 'Parent block';
  
  -- nested block
  DECLARE
    v_blockName VARCHAR2(50);
  BEGIN
    v_blockName := 'Nested block';

    dbms_output.put_line(v_blockName); -- prints the "Nested block"
  END;
  -- end of nested block

  dbms_output.put_line(v_blockName); -- prints the "Parent block"
  
END;

If you omit the DECLARE part in the nested block, it will overwrite the one in its parent.

DECLARE
  v_blockName VARCHAR2(50);
BEGIN
  v_blockName := 'Parent block';
  
  -- nested block
  BEGIN
    v_blockName := 'Nested block'; -- overwrites the variable from its parent

    dbms_output.put_line(v_blockName); -- prints "Nested block" 
  END;
  -- end of nested block

  dbms_output.put_line(v_blockName); -- prints "Nested block"
  
END;

Sometimes, it might be handy to use both variables (from the parent and in the actual nested block) and to have the same name for both of them. In this case, I recommend naming the blocks accordingly. This will let you refer to every variable individually (as long as it’s reachable within the block itself) using the DOT notation.

<<main_block>>
DECLARE
  v_blockName VARCHAR2(50);
BEGIN
  v_blockName := 'Parent block';
  
  <<nested_block>>
  DECLARE
    v_blockName VARCHAR2(50);
  BEGIN
    v_blockName := 'Nested block';

    <<another_nested_block>>
    DECLARE 
       v_blockName VARCHAR2(50);
    BEGIN
       v_blockName := 'Another nested block';

       -- define which variable you wanna use
       dbms_output.put_line(v_blockName); -- prints "Another nested block"
       dbms_output.put_line(another_nested_block.v_blockName); -- prints again "Another nested block" (same as previous)
       dbms_output.put_line(nested_block.v_blockName); -- prints "Nested block"
       dbms_output.put_line(MAIN_BLOCK.v_blockName); -- prints "Parent block"; as you can see the referencing is NOT case senstive
    END;
  END;
END;

When to use them?

There are, certainly, several cases when you should use nested blocks. One example might be when you do NOT want the whole program to fail into an exception because one part of the program (loop or any test) is failing. If any part is of your program is throwing an unexcepted exception, you can “secure” it by putting it in the nested block with its own exception handling and you are good to go 🙂

How about the performance?

There is no indication to suspect there is any negative performance impact. After all, nested blocks are pretty much the same as procedures or functions inside the package, except these are named compared to anonymous nested blocks.