PLSQL Fundamentals: Difference between revisions
Lsokolowski (talk | contribs)  | 
				Lsokolowski1 (talk | contribs) mNo edit summary  | 
				||
| Line 2: | Line 2: | ||
;title: PL/SQL Fundamentals  | ;title: PL/SQL Fundamentals  | ||
;author: Lukasz Sokolowski  | ;author: Lukasz Sokolowski  | ||
== PL/SQL Fundamentals ==  | == PL/SQL Fundamentals ==  | ||
| Line 15: | Line 15: | ||
{{Can I use your material}}  | {{Can I use your material}}  | ||
== Introduction   | == Introduction ==  | ||
* Aims and Objectives  | * Aims and Objectives  | ||
* Course Schedule  | * Course Schedule  | ||
| Line 22: | Line 22: | ||
* Responsibilities  | * Responsibilities  | ||
== What is PL/SQL?   | == What is PL/SQL? ==  | ||
* '''What''' is PL/SQL?  | * '''What''' is PL/SQL?  | ||
* '''Why''' Use PL/SQL?  | * '''Why''' Use PL/SQL?  | ||
| Line 31: | Line 31: | ||
* Update Example, Style Guide  | * Update Example, Style Guide  | ||
=== What is PL/SQL?   | === What is PL/SQL? ===  | ||
* Developed in 1991 by Oracle Corporation as a '''procedural language extension''' to SQL  | * Developed in 1991 by Oracle Corporation as a '''procedural language extension''' to SQL  | ||
* '''Integrates''' seamlessly with '''[[SQL_Programming|SQL]]'''    | * '''Integrates''' seamlessly with '''[[SQL_Programming|SQL]]'''    | ||
| Line 37: | Line 37: | ||
* Rich procedural extensions help in '''translating business logic''' within the Oracle Database  | * Rich procedural extensions help in '''translating business logic''' within the Oracle Database  | ||
=== Why Use PL/SQL?   | === Why Use PL/SQL? ===  | ||
* ''Procedural Language-Structured Query Language'' (PL/SQL)  | * ''Procedural Language-Structured Query Language'' (PL/SQL)  | ||
* Part of the Oracle Database product, '''no separate installation''' is required  | * Part of the Oracle Database product, '''no separate installation''' is required  | ||
| Line 47: | Line 47: | ||
* The '''built-in db optimizer''' refactors the code to improve the execution '''performance'''  | * The '''built-in db optimizer''' refactors the code to improve the execution '''performance'''  | ||
=== The advantages of PL/SQL as a language   | === The advantages of PL/SQL as a language ===  | ||
* '''Supports''' all types of SQL statements, data types, static SQL, and dynamic SQL  | * '''Supports''' all types of SQL statements, data types, static SQL, and dynamic SQL  | ||
* '''Runs''' on all platforms supported by the Oracle Database  | * '''Runs''' on all platforms supported by the Oracle Database  | ||
| Line 54: | Line 54: | ||
* Apps increase scalability by allowing '''multiple users''' to invoke the '''same program''' unit  | * Apps increase scalability by allowing '''multiple users''' to invoke the '''same program''' unit  | ||
=== PL/SQL accomplishments   | === PL/SQL accomplishments ===  | ||
* '''Not''' used to build '''user interfaces'''  | * '''Not''' used to build '''user interfaces'''  | ||
* '''For''' robust, secure, and portable '''interface layers'''  | * '''For''' robust, secure, and portable '''interface layers'''  | ||
| Line 65: | Line 65: | ||
** Procedures or subprograms can be '''invoked from client programs as executable statements'''  | ** Procedures or subprograms can be '''invoked from client programs as executable statements'''  | ||
=== PL/SQL program fundamental questions   | === PL/SQL program fundamental questions ===  | ||
* How do we '''handle''' an SQL '''execution''' in the program?  | * How do we '''handle''' an SQL '''execution''' in the program?  | ||
* How do we handle the '''procedural execution flow''' in the program?  | * How do we handle the '''procedural execution flow''' in the program?  | ||
| Line 71: | Line 71: | ||
* How do we '''trace and debug''' the program code?  | * How do we '''trace and debug''' the program code?  | ||
=== Block structure   | === Block structure ===  | ||
[[File:PlsqlBlockStr.jpg|480px]]  | [[File:PlsqlBlockStr.jpg|480px]]  | ||
=== Block structure Expl   | === Block structure Expl ===  | ||
PL/SQL program has '''4 sections'''  | PL/SQL program has '''4 sections'''  | ||
* Each section carries a '''specific objective'''  | * Each section carries a '''specific objective'''  | ||
| Line 88: | Line 88: | ||
* Keywords - ''EXCEPTION''; control lands into it and the appropriate '''exception handler''' is executed  | * Keywords - ''EXCEPTION''; control lands into it and the appropriate '''exception handler''' is executed  | ||
=== PL/SQL program categories   | === PL/SQL program categories ===  | ||
Block is the '''elementary unit''' of a program  | Block is the '''elementary unit''' of a program  | ||
* '''Groups''' a set of procedural statements  | * '''Groups''' a set of procedural statements  | ||
| Line 101: | Line 101: | ||
* '''Nested:''' block within another block, forms a nested block structure  | * '''Nested:''' block within another block, forms a nested block structure  | ||
=== Anonymous unit, example   | === Anonymous unit, example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
/* Enable the Serveroutput to display block messages */  | /* Enable the Serveroutput to display block messages */  | ||
| Line 121: | Line 121: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
== SQL Tools   | == SQL Tools ==  | ||
* Objectives  | * Objectives  | ||
* SQL Developer  | * SQL Developer  | ||
| Line 142: | Line 142: | ||
* SQL*Plus Commands  | * SQL*Plus Commands  | ||
== Variables   | == Variables ==  | ||
* Variables  | * Variables  | ||
* Datatypes  | * Datatypes  | ||
| Line 156: | Line 156: | ||
* Define and Undefine  | * Define and Undefine  | ||
-->  | -->  | ||
=== Variables, Datatypes, Setting   | === Variables, Datatypes, Setting ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
DECLARE  | DECLARE  | ||
| Line 170: | Line 170: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Constants   | === Constants ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
DECLARE  | DECLARE  | ||
| Line 182: | Line 182: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== %TYPE Attribute   | === %TYPE Attribute ===  | ||
* Syntax - '''referencing_item referenced_item%TYPE;'''  | * Syntax - '''referencing_item referenced_item%TYPE;'''  | ||
* Examples  | * Examples  | ||
| Line 200: | Line 200: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Variables Scope   | === Variables Scope ===    | ||
<syntaxhighlight lang="sql">-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-language-fundamentals.html#GUID-2FC17012-FC99-4614-90DD-ADC99F2EDBE9</syntaxhighlight>  | <syntaxhighlight lang="sql">-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-language-fundamentals.html#GUID-2FC17012-FC99-4614-90DD-ADC99F2EDBE9</syntaxhighlight>  | ||
=== Exercise   | === Exercise ===    | ||
Prepare necessary declarations for the draft or real invoice, print all of them to the screen(like below)    | Prepare necessary declarations for the draft or real invoice, print all of them to the screen(like below)    | ||
* variables, initialised (item price, item name)  | * variables, initialised (item price, item name)  | ||
| Line 277: | Line 277: | ||
-->  | -->  | ||
== SELECT INTO example   | == SELECT INTO example ==  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
DECLARE  | DECLARE  | ||
| Line 291: | Line 291: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== %ROWTYPE attribute   | === %ROWTYPE attribute ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
---- Record variable that represents a row of the table "dept", assigns values to its fields, and prints them  | ---- Record variable that represents a row of the table "dept", assigns values to its fields, and prints them  | ||
| Line 310: | Line 310: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
When the TOOSK's subordinate was hired?  | When the TOOSK's subordinate was hired?  | ||
* Use ''SELECT INTO''  | * Use ''SELECT INTO''  | ||
| Line 347: | Line 347: | ||
-->  | -->  | ||
== Conditional Statement   | == Conditional Statement ==  | ||
* IF Statement  | * IF Statement  | ||
* Case Statement  | * Case Statement  | ||
| Line 353: | Line 353: | ||
** <syntaxhighlight lang="sql" inline>-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-control-statements.html#GUID-B7DD4E62-3ED2-41E9-AAE5-90A78788BB31</syntaxhighlight>  | ** <syntaxhighlight lang="sql" inline>-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-control-statements.html#GUID-B7DD4E62-3ED2-41E9-AAE5-90A78788BB31</syntaxhighlight>  | ||
=== IF Statement   | === IF Statement ===  | ||
* IF THEN  | * IF THEN  | ||
* IF THEN ELSE  | * IF THEN ELSE  | ||
* IF THEN ELSIF  | * IF THEN ELSIF  | ||
=== IF THEN ELSE example   | === IF THEN ELSE example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
-- IF statement example  | -- IF statement example  | ||
| Line 389: | Line 389: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
Reuse variables exercise and apply this logic  | Reuse variables exercise and apply this logic  | ||
* When invoice is a draft set new variable 'Invoice Proforma Reference' with invoice number  | * When invoice is a draft set new variable 'Invoice Proforma Reference' with invoice number  | ||
| Line 413: | Line 413: | ||
-->  | -->  | ||
=== Case Statement   | === Case Statement ===  | ||
* Appropriate when a '''different action''' is to be taken '''for each alternative'''  | * Appropriate when a '''different action''' is to be taken '''for each alternative'''  | ||
* Two forms  | * Two forms  | ||
| Line 419: | Line 419: | ||
** '''Searched''', evaluates multiple conditions and chooses the first one that is true  | ** '''Searched''', evaluates multiple conditions and chooses the first one that is true  | ||
=== Simple Case example   | === Simple Case example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
DECLARE  | DECLARE  | ||
| Line 438: | Line 438: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Searched Case example   | === Searched Case example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
DECLARE  | DECLARE  | ||
| Line 460: | Line 460: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
Reuse invoice reference exercise and add this logic  | Reuse invoice reference exercise and add this logic  | ||
* One Franchisee can have 1-3 instances of invoicing tool  | * One Franchisee can have 1-3 instances of invoicing tool  | ||
| Line 513: | Line 513: | ||
-->  | -->  | ||
== Trapping Errors   | == Trapping Errors ==  | ||
* Exception  | * Exception  | ||
* System-defined  | * System-defined  | ||
| Line 519: | Line 519: | ||
* Propagation  | * Propagation  | ||
=== Exception   | === Exception ===  | ||
* Unusual and unexpected flow during '''runtime''' might result in abnormal '''termination'''  | * Unusual and unexpected flow during '''runtime''' might result in abnormal '''termination'''  | ||
** Such errors must be '''trapped''' and handled in the ''EXCEPTION'' section  | ** Such errors must be '''trapped''' and handled in the ''EXCEPTION'' section  | ||
| Line 532: | Line 532: | ||
** Retrieve the error code and message for the '''most recent''' exception  | ** Retrieve the error code and message for the '''most recent''' exception  | ||
=== System-defined   | === System-defined ===  | ||
* '''Defined and maintained''' implicitly by the Oracle Database, STANDARD package  | * '''Defined and maintained''' implicitly by the Oracle Database, STANDARD package  | ||
* db picks up the appropriate exception from the '''available list'''  | * db picks up the appropriate exception from the '''available list'''  | ||
* Associated with a '''negative error code''' (except 1 to 100) and short name (for handlers)  | * Associated with a '''negative error code''' (except 1 to 100) and short name (for handlers)  | ||
=== Using No Data Found   | === Using No Data Found ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
-- Example includes a SELECT statement to show details of employee 8265  | -- Example includes a SELECT statement to show details of employee 8265  | ||
| Line 563: | Line 563: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Solution - EXCEPTION with handler   | === Solution - EXCEPTION with handler ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
(...)  | (...)  | ||
| Line 580: | Line 580: | ||
*/  | */  | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
When did Blake come to the company?  | When did Blake come to the company?  | ||
<!-- Solution example  | <!-- Solution example  | ||
| Line 605: | Line 605: | ||
-->  | -->  | ||
=== Commonly used internal exceptions   | === Commonly used internal exceptions ===  | ||
{| class="wikitable"  | {| class="wikitable"  | ||
|-  | |-  | ||
| Line 637: | Line 637: | ||
|}  | |}  | ||
=== User exceptions   | === User exceptions ===  | ||
* Has specified '''name''' and associated '''error code'''  | * Has specified '''name''' and associated '''error code'''  | ||
* Raises statements '''in line''' with the implementation logic  | * Raises statements '''in line''' with the implementation logic  | ||
| Line 643: | Line 643: | ||
* ''RAISE'' statement in the ''BEGIN..END'' section  | * ''RAISE'' statement in the ''BEGIN..END'' section  | ||
=== User exceptions, 3 ways of declaring   | === User exceptions, 3 ways of declaring ===  | ||
EXCEPTION type '''variable''' in the declaration section  | EXCEPTION type '''variable''' in the declaration section  | ||
* Raise it '''explicitly''' in the program body (RAISE statement)  | * Raise it '''explicitly''' in the program body (RAISE statement)  | ||
| Line 653: | Line 653: | ||
RAISE_APPLICATION_ERROR - declares a '''dedicated''' error number and error message  | RAISE_APPLICATION_ERROR - declares a '''dedicated''' error number and error message  | ||
=== User-defined exception, example   | === User-defined exception, example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
/* Declare a bind variable */  | /* Declare a bind variable */  | ||
| Line 693: | Line 693: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
For each employee calculate the payout to commission ratio (ver1).  | For each employee calculate the payout to commission ratio (ver1).  | ||
<!--  | <!--  | ||
| Line 718: | Line 718: | ||
/  | /  | ||
-->  | -->  | ||
=== Raise Application Error   | === Raise Application Error ===  | ||
RAISE_APPLICATION_ERROR - procedure, raises a '''user-defined''' exception with a '''custom''' exception message  | RAISE_APPLICATION_ERROR - procedure, raises a '''user-defined''' exception with a '''custom''' exception message  | ||
* Exception can be '''optionally''' pre-defined (DECLARE)  | * Exception can be '''optionally''' pre-defined (DECLARE)  | ||
| Line 726: | Line 726: | ||
** '''last parameter''' - optional, adding to the current error '''stack'''  | ** '''last parameter''' - optional, adding to the current error '''stack'''  | ||
=== Example   | === Example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
---- Example  | ---- Example  | ||
| Line 758: | Line 758: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
Show employees who have joined the company after 1st of Nov, 1981.  | Show employees who have joined the company after 1st of Nov, 1981.  | ||
* Raise the exception if earlier  | * Raise the exception if earlier  | ||
| Line 783: | Line 783: | ||
-->  | -->  | ||
==== Example con't   | ==== Example con't ====  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
-- Same example, but with named exception  | -- Same example, but with named exception  | ||
| Line 831: | Line 831: | ||
-->  | -->  | ||
=== Nested Blocks Structure   | === Nested Blocks Structure ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
/*Parent block*/  | /*Parent block*/  | ||
| Line 856: | Line 856: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Nested Blocks Expl   | === Nested Blocks Expl ===  | ||
* Exception raised in '''inner''' block '''--->''' program control flows down to exception section of it  | * Exception raised in '''inner''' block '''--->''' program control flows down to exception section of it  | ||
* '''Inner''' block handles the exception, it's executed '''--->''' control '''returns''' to the next executable statement in the '''outer''' block  | * '''Inner''' block handles the exception, it's executed '''--->''' control '''returns''' to the next executable statement in the '''outer''' block  | ||
| Line 881: | Line 881: | ||
-->  | -->  | ||
== Cursors   | == Cursors ==  | ||
* Overview  | * Overview  | ||
* Execution cycle  | * Execution cycle  | ||
| Line 887: | Line 887: | ||
* FOR loop  | * FOR loop  | ||
=== Overview   | === Overview ===  | ||
* '''SQL''' is one of the critical parts of '''PL/SQL'''  | * '''SQL''' is one of the critical parts of '''PL/SQL'''  | ||
** '''Statements''' embedded within a PL/SQL block are '''executed as a cursor'''  | ** '''Statements''' embedded within a PL/SQL block are '''executed as a cursor'''  | ||
| Line 898: | Line 898: | ||
** We can explicitly declare an implicit cursor under the ''DECLARE'' section in ''SELECT'' query  | ** We can explicitly declare an implicit cursor under the ''DECLARE'' section in ''SELECT'' query  | ||
=== Execution cycle   | === Execution cycle ===  | ||
[[File:PlsqlCursorCycle.jpg|600px]]  | [[File:PlsqlCursorCycle.jpg|600px]]  | ||
=== Execution cycle Expl   | === Execution cycle Expl ===  | ||
Cursor '''moves''' through the following '''stages''' during execution  | Cursor '''moves''' through the following '''stages''' during execution  | ||
* implicit - all steps are carried out by db  | * implicit - all steps are carried out by db  | ||
| Line 914: | Line 914: | ||
* Releases the '''memory''' back to the UGA  | * Releases the '''memory''' back to the UGA  | ||
=== Attributes   | === Attributes ===  | ||
Hold the information about the cursor processing at each stage of its execution  | Hold the information about the cursor processing at each stage of its execution  | ||
* '''%ROWCOUNT''': number of rows, fetched until the '''last''' fetch    | * '''%ROWCOUNT''': number of rows, fetched until the '''last''' fetch    | ||
| Line 923: | Line 923: | ||
* '''%NOTFOUND''': FALSE/TRUE, cursor pointer switches but does '''not point''' to a record  | * '''%NOTFOUND''': FALSE/TRUE, cursor pointer switches but does '''not point''' to a record  | ||
=== Attributes, example   | === Attributes, example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
SET SERVEROUTPUT ON  | SET SERVEROUTPUT ON  | ||
| Line 974: | Line 974: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== FOR loop   | === FOR loop ===  | ||
CURSOR FOR loop  | CURSOR FOR loop  | ||
* Looping through '''all the records''' of a cursor object  | * Looping through '''all the records''' of a cursor object  | ||
| Line 983: | Line 983: | ||
** No need to explicitly open or close the cursor  | ** No need to explicitly open or close the cursor  | ||
=== FOR loop, example   | === FOR loop, example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
DECLARE  | DECLARE  | ||
| Line 1,009: | Line 1,009: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
Pick the attribute with the wrong value  | Pick the attribute with the wrong value  | ||
| Line 1,097: | Line 1,097: | ||
-->  | -->  | ||
== Procedures, Functions and Packages   | == Procedures, Functions and Packages ==  | ||
* Procedures  | * Procedures  | ||
* Functions  | * Functions  | ||
* Packages  | * Packages  | ||
=== Procedure   | === Procedure ===  | ||
'''Derivative''' of a PL/SQL block  | '''Derivative''' of a PL/SQL block  | ||
* Has a '''name''' and is '''stored persistently''' within the db  | * Has a '''name''' and is '''stored persistently''' within the db  | ||
| Line 1,108: | Line 1,108: | ||
* Promotes a '''modular''' programming, breaks down complex logic into '''simple routines'''  | * Promotes a '''modular''' programming, breaks down complex logic into '''simple routines'''  | ||
=== Procedure con't   | === Procedure con't ===  | ||
* Must be '''invoked''' from the executable section of a PL/SQL '''block'''  | * Must be '''invoked''' from the executable section of a PL/SQL '''block'''  | ||
* Executable '''directly''' from SQLPLUS (''EXECUTE'')  | * Executable '''directly''' from SQLPLUS (''EXECUTE'')  | ||
| Line 1,117: | Line 1,117: | ||
* ''RETURN'' - '''skips''' the further execution of the program and '''exits''' control  | * ''RETURN'' - '''skips''' the further execution of the program and '''exits''' control  | ||
=== Procedure parameter modes   | === Procedure parameter modes ===  | ||
{| class="wikitable"  | {| class="wikitable"  | ||
|-  | |-  | ||
| Line 1,133: | Line 1,133: | ||
|}  | |}  | ||
=== Procedure syntax   | === Procedure syntax ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
CREATE [OR REPLACE] PROCEDURE [Procedure Name] [Parameter List]  | CREATE [OR REPLACE] PROCEDURE [Procedure Name] [Parameter List]  | ||
| Line 1,146: | Line 1,146: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Procedure example   | === Procedure example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
---- Converts GeoJSON points into WKT(Well-known text)  | ---- Converts GeoJSON points into WKT(Well-known text)  | ||
| Line 1,171: | Line 1,171: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Calling Procedures   | === Calling Procedures ===  | ||
* From '''SQL*Plus'''  | * From '''SQL*Plus'''  | ||
* Inside of PL/SQL '''block'''  | * Inside of PL/SQL '''block'''  | ||
=== SQLPlus   | === SQLPlus ===  | ||
* Initial setup  | * Initial setup  | ||
* Calling  | * Calling  | ||
==== Initial setup   | ==== Initial setup ====  | ||
  sys as sysdba  |   sys as sysdba  | ||
  asdf  |   asdf  | ||
| Line 1,185: | Line 1,185: | ||
  SQL> show user  |   SQL> show user  | ||
==== Calling   | ==== Calling ====  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
---- Calling procedure from PL*SQL  | ---- Calling procedure from PL*SQL  | ||
| Line 1,207: | Line 1,207: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Calling procedure from anonymous unit   | === Calling procedure from anonymous unit ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
BEGIN  | BEGIN  | ||
| Line 1,216: | Line 1,216: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
Wrap all the 'Invoice Reference' related code into procedure  | Wrap all the 'Invoice Reference' related code into procedure  | ||
<!-- Solution example  | <!-- Solution example  | ||
| Line 1,349: | Line 1,349: | ||
* When '''invoked from PL/SQL''', the return type should be a '''valid PL/SQL type'''  | * When '''invoked from PL/SQL''', the return type should be a '''valid PL/SQL type'''  | ||
=== Function syntax   | === Function syntax ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
CREATE [OR REPLACE] FUNCTION [Function Name] [Parameter List]  | CREATE [OR REPLACE] FUNCTION [Function Name] [Parameter List]  | ||
| Line 1,366: | Line 1,366: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Function example   | === Function example ===  | ||
<syntaxhighlight lang="sql">  | <syntaxhighlight lang="sql">  | ||
---- Get the date of birth from pesel  | ---- Get the date of birth from pesel  | ||
| Line 1,408: | Line 1,408: | ||
</syntaxhighlight>  | </syntaxhighlight>  | ||
=== Exercise   | === Exercise ===  | ||
# Wrap all the 'Franchisee' related code into function  | # Wrap all the 'Franchisee' related code into function  | ||
#* HINT: redesign printing code (array?)  | #* HINT: redesign printing code (array?)  | ||
| Line 1,538: | Line 1,538: | ||
-->  | -->  | ||
=== Packages   | === Packages ===  | ||
<syntaxhighlight lang="sql">-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-packages.html#GUID-C285EC5A-BE50-4192-A88E-48C0778B34E0</syntaxhighlight>  | <syntaxhighlight lang="sql">-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-packages.html#GUID-C285EC5A-BE50-4192-A88E-48C0778B34E0</syntaxhighlight>  | ||
<!--  | <!--  | ||
Latest revision as of 23:18, 29 October 2025
- title
 - PL/SQL Fundamentals
 - author
 - Lukasz Sokolowski
 
PL/SQL Fundamentals
PL/SQL Fundamentals Training Materials
IMPORTANT NOTE for trainers only: Please DO NOT change these materials, especially the EXERCISES, without direct permission from: GRZEGORZ PRUSZCZYNSKI or LUKASZ SOKOLOWSKI.
Copyright Notice
Copyright © 2004-2025 by NobleProg Limited All rights reserved.
This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise.
Introduction
- Aims and Objectives
 - Course Schedule
 - Introductions
 - Pre-requisites
 - Responsibilities
 
What is PL/SQL?
- What is PL/SQL?
 - Why Use PL/SQL?
 - Block Structure
 - Displaying a Message
 - Sample Code
 - Setting SERVEROUTPUT
 - Update Example, Style Guide
 
What is PL/SQL?
- Developed in 1991 by Oracle Corporation as a procedural language extension to SQL
 - Integrates seamlessly with SQL
 - Powerful language to construct the data access layer
 - Rich procedural extensions help in translating business logic within the Oracle Database
 
Why Use PL/SQL?
- Procedural Language-Structured Query Language (PL/SQL)
 - Part of the Oracle Database product, no separate installation is required
 - Translates business logic in the db and exposes the program interface layer to the application
 - SQL is purely a data access language that directly interacts with the db
 - PL/SQL is a programming language
- Multiple SQLs and procedural statements can be grouped in a program unit
 - Portable between Oracle Databases
 
 - The built-in db optimizer refactors the code to improve the execution performance
 
The advantages of PL/SQL as a language
- Supports all types of SQL statements, data types, static SQL, and dynamic SQL
 - Runs on all platforms supported by the Oracle Database
 - Performance can be improved by the use of bind variables in direct SQL queries
 - Supports the object-oriented model of the Oracle Database
 - Apps increase scalability by allowing multiple users to invoke the same program unit
 
PL/SQL accomplishments
- Not used to build user interfaces
 - For robust, secure, and portable interface layers
- Can be exposed to a high-level programming language
 
 - Procedural: list of operations that can execute sequentially
- SQL just declares, PL/SQL adds selective and iterative constructs
 
 - Db programming: server side programs run faster than the middle-tier
- Easy code maintenance, needs to be re-written less frequently
 
 - Integral: apps developers can easily integrate it with other high-level programming interfaces (Java, C++, or .NET)
- Procedures or subprograms can be invoked from client programs as executable statements
 
 
PL/SQL program fundamental questions
- How do we handle an SQL execution in the program?
 - How do we handle the procedural execution flow in the program?
 - Does the program handle the exceptions?
 - How do we trace and debug the program code?
 
Block structure
Block structure Expl
PL/SQL program has 4 sections
- Each section carries a specific objective
 - Must exist in the same sequence in a program
 
Header: optional, required for named blocks (procedures, functions, and triggers)
- Contains the program name, the program's owner, and the parameter specification
 
Declaration: optional, declares local variables, cursors, and local subprograms
- Keywords - DECLARE; can be skipped if no variables
 
Execution: procedural, comprises the main program body and an exception
- Keywords - BEGIN, END; must contain at least one executable statement
 - Statements are parsed and sequentially executed by the engine
 
Exception: optional, for various errors, occurable in the program leading to abnormal termination
- Keywords - EXCEPTION; control lands into it and the appropriate exception handler is executed
 
PL/SQL program categories
Block is the elementary unit of a program
- Groups a set of procedural statements
 
Number of sections defines type of the unit
- Anonymous: simplest; has no name, has DECLARE-BEGIN-END skeleton
- Current execution as standalone block or embedded locally within another unit
 - Cannot be stored in the db
 
 - Named: routine stored persistently in db as a schema object
- Invoked from db session or by another unit
 - Can be a function, procedure, trigger, or package
 
 - Nested: block within another block, forms a nested block structure
 
Anonymous unit, example
/* Enable the Serveroutput to display block messages */
-- SET SERVEROUTPUT ON;
/* Start the PL/SQL block */
DECLARE
/* Declare a local variable and initialize with a default value */
   MY_STR VARCHAR2(80) := 'Yes, I do like PL/SQL';
BEGIN
/* Print the result */
   DBMS_OUTPUT.PUT_LINE( 'Do you like it? ' || MY_STR );
END;
/
-----------------------------------
-- Do you like it? Yes, I do like PL/SQL
-- PL/SQL procedure successfully completed.
SQL Tools
- Objectives
 - SQL Developer
 - SQL Developer - Connection
 - Viewing Table Information
 - Using SQL, SQL Developer - Query
 - SQL*Plus Login
 - Direct Connection
 - Using SQL*Plus
 - Ending the Session
 - SQL*Plus Commands
 - SQL*Plus Environment
 - SQL*Plus Prompt
 - Finding Information about Tables
 - Getting Help
 - Using SQL Files
 - iSQL*Plus, Entity Models
 - Course Tables Handout
 - SQL Statement Syntax
 - SQL*Plus Commands
 
Variables
- Variables
 - Datatypes
 - Setting Variables
 - Constants
 - Local and Global Variables
 - %Type Variables
 
Variables, Datatypes, Setting
DECLARE
  part_number       NUMBER(6);     -- SQL data type, NULL
  part_name         VARCHAR2(20) := 'Gauss Rifle';  -- SQL data type, initialized with value
  in_stock          BOOLEAN;       -- PL/SQL-only data type, NULL(unknown)
  part_price        NUMBER(6,2);   -- SQL data type
  part_description  VARCHAR2(50);  -- SQL data type
BEGIN
  NULL;
END;
/
Constants
DECLARE
  credit_limit     CONSTANT REAL    := 5000.00;  -- SQL data type
  max_days_in_year CONSTANT INTEGER := 366;      -- SQL data type
  urban_legend     CONSTANT BOOLEAN := FALSE;    -- PL/SQL-only data type
BEGIN
  NULL;
END;
/
%TYPE Attribute
- Syntax - referencing_item referenced_item%TYPE;
 - Examples
 
DECLARE
  ---- Variable of Same Type as Column
  emp_name  emp.ename%TYPE;
  name     VARCHAR(25) NOT NULL := 'Bond';
  ---- Variable of Same Type as Another Variable
  surname  name%TYPE := 'Dick';
BEGIN
  DBMS_OUTPUT.PUT_LINE('Full name =' || emp_name);
  DBMS_OUTPUT.PUT_LINE('name=' || name);
  DBMS_OUTPUT.PUT_LINE('surname=' || surname);
END;
/
Variables Scope
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-language-fundamentals.html#GUID-2FC17012-FC99-4614-90DD-ADC99F2EDBE9
Exercise
Prepare necessary declarations for the draft or real invoice, print all of them to the screen(like below)
- variables, initialised (item price, item name)
 - vars, not initialised (invoice's unique number, invoice type(draft or real), final cost, items total, date of issue, amount, VAT rate, Items)
 - constants (tax rate, item number)
 - inheriting type od data (Items from Final Cost)
 
/* ---- HEADERS ---- Date of Issue: present_year-present_month-present_day Invoice number: INV201 Invoice type: draft ---- INVOICE ITEMS ---- Item Number Item Name Amount Price Tax Rate Final Cost 190.228.09 Gaus Rifle 20 800 0,20 16000 SUMMARY: VAT rate: 20% Items: 16000 Items total: 19200 (...) */
SELECT INTO example
DECLARE
  bonus   NUMBER(8,2);
BEGIN
  SELECT sal * 0.10 INTO bonus
  FROM emp
  WHERE id = 7900;
  DBMS_OUTPUT.PUT_LINE('bonus = ' || TO_CHAR(bonus));
END;
/
%ROWTYPE attribute
---- Record variable that represents a row of the table "dept", assigns values to its fields, and prints them
DECLARE
  dept_rec dept%ROWTYPE;
BEGIN
  -- Assign values to fields:  
  dept_rec.deptno   := 50;
  dept_rec.dname    := 'Administration';
  dept_rec.loc      := 'HongKong';
 
  -- Print fields: 
  DBMS_OUTPUT.PUT_LINE('dept_id:   ' || dept_rec.deptno);
  DBMS_OUTPUT.PUT_LINE('dept_name: ' || dept_rec.dname);
  DBMS_OUTPUT.PUT_LINE('loc:    ' || dept_rec.loc);
END;
/
Exercise
When the TOOSK's subordinate was hired?
- Use SELECT INTO
 - Show the result like below
 
/* Subordinate name = THATCHER Hiredate = 80/12/17 */
Conditional Statement
- IF Statement
 - Case Statement
 - More here
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-control-statements.html#GUID-B7DD4E62-3ED2-41E9-AAE5-90A78788BB31
 
IF Statement
- IF THEN
 - IF THEN ELSE
 - IF THEN ELSIF
 
IF THEN ELSE example
-- IF statement example
DECLARE
  PROCEDURE p (
    sales  NUMBER,
    quota  NUMBER,
    emp_id NUMBER
  )
  IS
    bonus  NUMBER := 0;
  BEGIN
    IF sales > (quota + 200) THEN
      bonus := (sales - quota)/4;
    ELSE
      bonus := 50;
    END IF;
 
    DBMS_OUTPUT.PUT_LINE('bonus = ' || bonus);
 
    UPDATE emp
    SET sal = sal + bonus 
    WHERE id = emp_id;
  END p;
BEGIN
  p(10100, 10000, 7369);
  p(10500, 10000, 121);
END;
/
Exercise
Reuse variables exercise and apply this logic
- When invoice is a draft set new variable 'Invoice Proforma Reference' with invoice number
 - Otherwise set new variable 'Invoice Reference'
 
Case Statement
- Appropriate when a different action is to be taken for each alternative
 - Two forms
- Simple, evaluates a single expression and compares it to several potential values
 - Searched, evaluates multiple conditions and chooses the first one that is true
 
 
Simple Case example
DECLARE
  sal_grade NUMBER;
BEGIN
  sal_grade := 2;
  CASE sal_grade
    WHEN 1 THEN DBMS_OUTPUT.PUT_LINE('Poor');
    WHEN 2 THEN DBMS_OUTPUT.PUT_LINE('Peanuts');
    WHEN 3 THEN DBMS_OUTPUT.PUT_LINE('Still Peanuts');
    WHEN 4 THEN DBMS_OUTPUT.PUT_LINE('Pineapples');
    WHEN 5 THEN DBMS_OUTPUT.PUT_LINE('Coconuts');
    ELSE DBMS_OUTPUT.PUT_LINE('No such grade');
  END CASE;
END;
/
Searched Case example
DECLARE
PROCEDURE print_bool (pb BOOLEAN)
AS
BEGIN
  DBMS_OUTPUT.PUT_LINE (
    CASE
      WHEN pb IS NULL THEN 'Unknown'
      WHEN pb THEN 'True'
      WHEN NOT pb THEN 'False'
    END
  );
END;
BEGIN
  print_bool(TRUE);
  print_bool(FALSE);
  print_bool(NULL);
END;
Exercise
Reuse invoice reference exercise and add this logic
- One Franchisee can have 1-3 instances of invoicing tool
 - For each instance set 3 new variables
- 'tool_key_var1' - set it with a string 'tool_key1_' concatenated with Franchsiee's Name(new var)
 - 'tool_secret_var1' - set it with 'tool_secret1_' with F's name
 - 'tool_acc_var1' - set 'tool_account1_' with F's name
 
 - Check which instance will be used to issue invoice (new var)
- Default should say 'No such tool exists. Please contact the administrator.'
 
 
Trapping Errors
- Exception
 - System-defined
 - User-defined
 - Propagation
 
Exception
- Unusual and unexpected flow during runtime might result in abnormal termination
- Such errors must be trapped and handled in the EXCEPTION section
 
 - Exceptions suppress the abnormal termination with an alternative and secured action
 - Important step in db programming
 - Unhandled exceptions
- Can result in unplanned application outages
 - Impact business continuity
 - Frustrate end users
 
 - System-defined(implicitly raised) and user-defined(declared and raised in unit)
 - Utility functions - SQLCODE and SQLERRM
- Retrieve the error code and message for the most recent exception
 
 
System-defined
- Defined and maintained implicitly by the Oracle Database, STANDARD package
 - db picks up the appropriate exception from the available list
 - Associated with a negative error code (except 1 to 100) and short name (for handlers)
 
Using No Data Found
-- Example includes a SELECT statement to show details of employee 8265
-- Raises NO_DATA_FOUND - employee id 8265 doesn't exist
DECLARE
   V_ENAME VARCHAR2 (100);
   V_HIRED DATE;
   V_EMPNO NUMBER := 8265;
BEGIN
/*Write a SELECT statement */
   SELECT ENAME, HIREDATE
   INTO V_ENAME, V_HIRED
   FROM EMP
   WHERE ID = V_EMPNO;
END;
/
-----------------------------------
/*
DECLARE
(...)
ERROR at line 7:
ORA-01403: no data found
ORA-06512: at line 7
*/
Solution - EXCEPTION with handler
(...)
EXCEPTION
   /* Exception Handler */
   WHEN NO_DATA_FOUND THEN
   /* Display an informative message */
   DBMS_OUTPUT.PUT_LINE ('No Employee exists with the id ' || V_EMPNO);
END
/
-----------------------------------
/*
No Employee exists with the id 8265
PL/SQL procedure successfully completed.
*/
Exercise
When did Blake come to the company?
Commonly used internal exceptions
| Error, ORA-_ | Named exception | Raised when | 
|---|---|---|
| 00001 | DUP_VAL_ON_INDEX | Duplicate value exists | 
| 01001 | INVALID_CURSOR | Cursor is invalid | 
| 01012 | NOT_LOGGED_ON | User is not logged in | 
| 01017 | LOGIN_DENIED | System error occurred | 
| 01403 | NO_DATA_FOUND | The query returns no data | 
| 01422 | TOO_MANY_ROWS | A single row query returns multiple rows | 
| 01476 | ZERO_DIVIDE | An attempt was made to divide a number by zero | 
| 01722 | INVALID_NUMBER | The number is invalid | 
| 06504 | ROWTYPE_MISMATCH | Mismatch occurred in row type | 
| 06511 | CURSOR_ALREADY_OPEN | Cursor is already open | 
| 06531 | COLLECTION_IS_NULL | Working with NULL collection | 
| 06532 | SUBSCRIPT_OUTSIDE_LIMIT | Collection index out of range | 
| 06533 | SUBSCRIPT_BEYOND_COUNT | Collection index out of count | 
User exceptions
- Has specified name and associated error code
 - Raises statements in line with the implementation logic
 - Standardizes the exception handling to alter the program execution logic
 - RAISE statement in the BEGIN..END section
 
User exceptions, 3 ways of declaring
EXCEPTION type variable in the declaration section
- Raise it explicitly in the program body (RAISE statement)
 - Handle it in the EXCEPTION section, no error code is involved
 
EXCEPTION variable associated with standard error number
- using PRAGMA EXCEPTION_INIT
 - PRAGMA - directive to the compiler, manipulates the behavior during compilation (not at the time of execution)
 - Also mapping to non-predefined exception (standard errors not defined as PL/SQL exceptions)
 
RAISE_APPLICATION_ERROR - declares a dedicated error number and error message
User-defined exception, example
/* Declare a bind variable */
VARIABLE B_NO NUMBER;
/* Assign negative value to B_NO */
EXEC :B_NO := -4;
-- EXEC :B_NO := 9;
DECLARE
   I_NO NUMBER := :B_NO;
   I_SQR NUMBER;
   /* Declare an exception variable */
   NORESU EXCEPTION;
BEGIN
   /* Raise the exception if B_NO equals negative value */
   IF I_NO < 0 THEN
      RAISE NORESU;
   END IF;
   I_SQR := SQRT(I_NO);
   DBMS_OUTPUT.PUT_LINE('The result : ' || I_SQR);
EXCEPTION
   /* Exception handler for NORESU exception */
   WHEN NORESU THEN
      DBMS_OUTPUT.PUT_LINE('Number cannot be negative');
END;
/
---------------------------
/*
Number cannot be negative
PL/SQL procedure successfully completed.
*/
---------------------------
/*
The result : 3
PL/SQL procedure successfully completed.
*/
Exercise
For each employee calculate the payout to commission ratio (ver1).
Raise Application Error
RAISE_APPLICATION_ERROR - procedure, raises a user-defined exception with a custom exception message
- Exception can be optionally pre-defined (DECLARE)
 - Syntax: 
RAISE_APPLICATION_ERROR (error_number, error_message[, {TRUE | FALSE}])- error_number - mandatory parameter, values range 20000-20999
 - error_message - user-defined, appears along with the exception
 - last parameter - optional, adding to the current error stack
 
 
Example
---- Example
-- Show employees who earn more than 2000 (excluding commision).
-- The program must raise an exception if monies are less than the given amount.
DECLARE
   G_MONEY NUMBER := 2000;
/* Declare a cursor to filter employees */
   CURSOR C_EMP IS
    SELECT id, ename, sal
    FROM emp;
BEGIN
   FOR E IN C_EMP
   LOOP
   /* Raise exception, if monies are less than 2000 */
      IF e.sal < g_money THEN
        /* Exception name is not used to create the exception handler */
        RAISE_APPLICATION_ERROR (-20008, 'Gets less, show the other one!');
      ELSE 
	DBMS_OUTPUT.PUT_LINE( e.ename || ' gets ' || e.sal);
      END IF;
   END LOOP;
END;
/
---------------
/*
Error starting at line : 171 in command -
ORA-20008: Gets less, show the other one!
ORA-06512: at line 12
*/
Exercise
Show employees who have joined the company after 1st of Nov, 1981.
- Raise the exception if earlier
 
Example con't
-- Same example, but with named exception
(...)
/* Declare the exception var */
  INVAL_EMP_SAL EXCEPTION;
  PRAGMA EXCEPTION_INIT(INVAL_EMP_SAL, -20008);
(...)
    IF e.sal < g_money THEN
	   RAISE INVAL_EMP_SAL;
    ELSE
(...)
  END LOOP;
EXCEPTION
  WHEN INVAL_EMP_SAL THEN
    DBMS_OUTPUT.PUT_LINE(SQLERRM || 'Gets less, show the other one!');
END;
/
Nested Blocks Structure
/*Parent block*/
DECLARE
...
BEGIN
   /* Outer block executable statements */
...
   /* Child Block */
   DECLARE
  ...
   BEGIN
      ...
      /* Inner block executable statements */
      ...
   EXCEPTION
      /* Inner block exception handlers */
   END;
   ...
   /* Outer block executable statements */
EXCEPTION
/* Outer block exception handlers */
END;
Nested Blocks Expl
- Exception raised in inner block ---> program control flows down to exception section of it
 - Inner block handles the exception, it's executed ---> control returns to the next executable statement in the outer block
 - Inner block doesn't handle the exception ---> control searches further and propagates to the exception section of the outer block
- The execution of the outer block is skipped and the program control lands straight in to the exception section
 
 - Control will continue to propagate the unhandled exception in the outer blocks
- Until the appropriate one is found and handled
 
 
Cursors
- Overview
 - Execution cycle
 - Attributes
 - FOR loop
 
Overview
- SQL is one of the critical parts of PL/SQL
- Statements embedded within a PL/SQL block are executed as a cursor
 
 - Cursor - private memory area, temporarily allocated in the session's User Global Area (UGA)
- Stores the result set retrieved from the SQL execution and cursor attributes
 
 - Cursors can be implicit or explicit
 - Implicit - is always created for all the included SQL statements
- Its lifecycle is maintained by db
 
 - Explicit - execution cycle can be controlled by the user
- We can explicitly declare an implicit cursor under the DECLARE section in SELECT query
 
 
Execution cycle
Execution cycle Expl
Cursor moves through the following stages during execution
- implicit - all steps are carried out by db
 
OPEN - allocates the context area in the session's UGA
- Starts with parsing and binding, followed by statement execution
 - In SELECT the record pointer points to the first record in the result set
 
FETCH - pulls the data from the query result set
- In multi-record set, the record pointer moves incrementally with every fetch
 - Is alive until the last record is reached
 
CLOSE - closes the cursor
- Flushes the context area
 - Releases the memory back to the UGA
 
Attributes
Hold the information about the cursor processing at each stage of its execution
- %ROWCOUNT: number of rows, fetched until the last fetch
- or impacted by the last DML operation (SELECT, DML)
 
 - %ISOPEN: TRUE/FALSE, cursor open or not, implicit is always FALSE
- The only one accessible outside the cycle (!)
 
 - %FOUND: TRUE/FALSE, fetch operation switches and points to a record or not
 - %NOTFOUND: FALSE/TRUE, cursor pointer switches but does not point to a record
 
Attributes, example
SET SERVEROUTPUT ON
DECLARE
/* Declare a cursor to select employees info */
   CURSOR MY_C_EMP IS
      SELECT ID,ENAME
       FROM EMP;
   L_EMPNO EMP.ID%TYPE;
   L_ENAME EMP.ENAME%TYPE;
BEGIN
/* Check if the cursor is already open */
   IF NOT MY_C_EMP%ISOPEN THEN
     DBMS_OUTPUT.PUT_LINE('--- Employee Info ---');
   END IF;
/* Open the cursor and iterate in a loop */
   OPEN MY_C_EMP;
   LOOP
/* Fetch the cursor data into local variables */
   FETCH MY_C_EMP INTO L_EMPNO, L_ENAME;
   EXIT WHEN MY_C_EMP%NOTFOUND;
/* Display the employee info */
      DBMS_OUTPUT.PUT_LINE(chr(10) || 'Show Info for employee: ' || MY_C_EMP%ROWCOUNT);
      DBMS_OUTPUT.PUT_LINE('Id: ' || L_EMPNO);
      DBMS_OUTPUT.PUT_LINE('Name: ' || L_ENAME);
   END LOOP;
END;
/
/*
--- Employee Info ---
Show Info for employee:1
Id:7839
Name:BUSH
Show Info for employee:2
Id:7566
Name:PUTIN
(...)
PL/SQL procedure successfully completed.
*/
FOR loop
CURSOR FOR loop
- Looping through all the records of a cursor object
 - Reduces the overhead of manually specifying the OPEN, FETCH, and CLOSE stages
 - Compacts the code when working with multi-row explicit cursors
 - No need to declare the block variables to capture the cursor columns
- Index implicitly acts as a record of the cursor type
 - No need to explicitly open or close the cursor
 
 
FOR loop, example
DECLARE
/* Declare an explicit cursor to select employee info */
   CURSOR C_EMP IS
      SELECT ename, sal
      FROM emp;
BEGIN
/* Using the cursor C_EMP directly */
   FOR EMP IN C_EMP
   LOOP
/* Display result */
   DBMS_OUTPUT.PUT_LINE(EMP.ename || ' gains ' || EMP.sal || ' monthly');
   END LOOP;
END;
/
/*
BUSH gains 5000 monthly
PUTIN gains 2975 monthly
CARNEGIE gains 3000 monthly
FORD gains 1100 monthly
(...)
*/
Exercise
Pick the attribute with the wrong value
| Query | Cursor attributes | 
|---|---|
  BEGIN
  (...)
  SELECT ENAME, DEPTNO
  INTO V_ENAME, V_DEPTNO
  FROM EMP
  WHERE ID = 7900;
  (...)
  END;
 | 
  | 
Procedures, Functions and Packages
- Procedures
 - Functions
 - Packages
 
Procedure
Derivative of a PL/SQL block
- Has a name and is stored persistently within the db
 - Schema object, primarily used to implement business logic on the server side
 - Promotes a modular programming, breaks down complex logic into simple routines
 
Procedure con't
- Must be invoked from the executable section of a PL/SQL block
 - Executable directly from SQLPLUS (EXECUTE)
 - Can not be called from a SELECT statement
 - Can optionally accept parameters - IN, OUT, or IN OUT mode
 - Can't return a value
- OUT params - is the only way (not via RETURN [value])
 
 - RETURN - skips the further execution of the program and exits control
 
Procedure parameter modes
| IN | OUT | IN OUT | 
|---|---|---|
| Default | Has to be explicitly defined | Has to be explicitly defined | 
| Value passed to the program from the calling environment | Value returned back to the calling environment | Passes a value from the calling env to the program or returns value to the calling env | 
| Passed by reference | Passed by value | Passed by value | 
| Constant, literal, initialized variable | Uninitialized variable | Initialized variable | 
| Can hold default value | No default value | No default value | 
Procedure syntax
CREATE [OR REPLACE] PROCEDURE [Procedure Name] [Parameter List]
[AUTHID DEFINER | CURRENT_USER]
IS
  [Declaration Statements]
BEGIN
 [Executable Statements]
EXCEPTION
 [Exception handlers]
END [Procedure Name];
Procedure example
---- Converts GeoJSON points into WKT(Well-known text)
-- GeoJSON is a standard format for encoding various of geographic data structures
-- WKT is a text markup language for representing vector geometry objects on a map
CREATE OR REPLACE PROCEDURE P_GJSON2WKT (POINTS_STR VARCHAR2, COORDINATES_STR VARCHAR2)
IS
/*Declare the local variables*/
   RESULT_POINTS_STR VARCHAR2(100);
   RESULT_COORDS_STR VARCHAR2(100);
BEGIN
   -- TRANSLATE( '[127.8, 75.6]', '[,]', '( )' )
   RESULT_POINTS_STR := TRANSLATE( POINTS_STR, '[,]', '( )' );
   DBMS_OUTPUT.PUT_LINE('Points : ' || RESULT_POINTS_STR);
   -- TRANSLATE( '(127.8 75.6)', '( )', '[,]' )
   RESULT_COORDS_STR := TRANSLATE( COORDINATES_STR, '( )', '[,]' );
   DBMS_OUTPUT.PUT_LINE('Coordinates : ' || RESULT_COORDS_STR);
END;
/
---------------
/*
Procedure P_GJSON2WKT compiled
*/
Calling Procedures
- From SQL*Plus
 - Inside of PL/SQL block
 
SQLPlus
- Initial setup
 - Calling
 
Initial setup
sys as sysdba asdf SQL> conn mike/mike@localhost/xepdb1 SQL> show user
Calling
---- Calling procedure from PL*SQL
SQL> SET SERVEROUTPUT ON
/* Session variable for the input */
SQL> VARIABLE P_STR VARCHAR2(100);
/* Test value */
SQL> EXECUTE :P_STR := '[127.8, 75.6]';
-- PL/SQL procedure successfully completed.
SQL> VARIABLE C_STR VARCHAR2(100);
SQL> EXECUTE :C_STR := '(127.8 75.6)';
-- PL/SQL procedure successfully completed.
/* Call the procedure P_GJSON2WKT */
SQL> EXECUTE P_GJSON2WKT(:P_STR, :C_STR);
/*
Points : (127.8  75.6)
Coordinates : [127.8,75.6]
PL/SQL procedure successfully completed.
*/
Calling procedure from anonymous unit
BEGIN
   /* Call the P_GJSON2WKT procedure */
   P_GJSON2WKT('[127.8, 75.6]', '(271.3 56.4)');
END;
/
Exercise
Wrap all the 'Invoice Reference' related code into procedure
Creating functions
Named derivative of a PL/SQL block, physically stored in db schema
- Accepts parameters in all modes(IN, OUT, and IN OUT) and mandatorily returns a value
 - Can be called in SQL statements (SELECT and DMLs)
- Must accept only IN parameters of valid SQL types
 - Function body must obey the database purity rules
 - Its return type should be a valid SQL data type
 
 - When invoked from PL/SQL, the return type should be a valid PL/SQL type
 
Function syntax
CREATE [OR REPLACE] FUNCTION [Function Name] [Parameter List]
RETURN [Data type]
[AUTHID DEFINER | CURRENT_USER]
[DETERMINISTIC | PARALLEL_ENABLED | PIPELINED]
[RESULT_CACHE [RELIES_ON (table name)]]
IS
  [Declaration Statements]
BEGIN
 [Executable Statements]
  RETURN [Value]
EXCEPTION
 [Exception handlers]
END [Function Name];
Function example
---- Get the date of birth from pesel
-- 82010901858
-- 820109
-- 82-01-09
--
CREATE OR REPLACE FUNCTION getDateOfBirthFromPesel (P_NUM NUMBER)
RETURN VARCHAR2
IS
  yearFromPesel     VARCHAR2(4); -- peselFromForm.substr(0, 2);
  monthFromPesel    yearFromPesel%TYPE; -- peselFromForm.substr(2, 2);
  dayFromPesel      yearFromPesel%TYPE; -- peselFromForm.substr(4, 2);
  D_BIRTH           VARCHAR2(100);
BEGIN
  /* On production we should validate pesel first */
  /* We should also consider the centuries bit first */
  yearFromPesel     := substr(to_char(P_NUM), 1, 2);
  monthFromPesel    := substr(to_char(P_NUM), 3, 2);
  dayFromPesel      := substr(to_char(P_NUM), 5, 2);
  D_BIRTH := yearFromPesel || '-' || monthFromPesel || '-' || dayFromPesel;
  
  RETURN D_BIRTH;
END;
/
-------------
-- Function GETDATEOFBIRTHFROMPESEL compiled
---------------------------------------------
---- MINI PROGRAM FOR EXECUTING OUR FUNC
---------------------------------------------
DECLARE
   DBIRTH VARCHAR2(100);
BEGIN
   DBIRTH := getDateOfBirthFromPesel(82010901858);
   DBMS_OUTPUT.PUT_LINE('Date of birth from pesel : ' || DBIRTH);
END;
/
---------------------------------------------
Exercise
- Wrap all the 'Franchisee' related code into function
- HINT: redesign printing code (array?)
 -- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-collections-and-records.html#GUID-8060F01F-B53B-48D4-9239-7EA8461C2170
 - Validate PESEL, Polish social number
 
Packages
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-packages.html#GUID-C285EC5A-BE50-4192-A88E-48C0778B34E0
Triggers
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-triggers.html#GUID-217E8B13-29EF-45F3-8D0F-2384F9F1D231
Dynamic SQL
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/dynamic-sql.html#GUID-7E2F596F-9CA3-4DC8-8333-0C117962DB73
Collections
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-collections-and-records.html#GUID-7115C8B6-62F9-496D-BEC3-F7441DFE148A
Data Types
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-data-types.html#GUID-391C58FD-16AF-486C-AF28-173E309CDBA5