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.
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.