PLSQL Fundamentals
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-2023 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