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