0% found this document useful (0 votes)
49 views77 pages

Chap2 Anglais BDA 231102 210223

This document provides an overview of PL/pgSQL, the procedural programming language for PostgreSQL. It discusses: 1) PL/pgSQL allows writing procedures, functions, and triggers to extend PostgreSQL's functionality beyond standard SQL queries. This allows executing multiple statements together efficiently rather than individual queries. 2) Key advantages include reducing round trips between applications and the database server and avoiding transferring result sets. 3) PL/pgSQL code is organized into blocks, which can be anonymous or named functions and procedures. Variables are declared and used to store temporary data within blocks.

Uploaded by

Essadik Dev
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views77 pages

Chap2 Anglais BDA 231102 210223

This document provides an overview of PL/pgSQL, the procedural programming language for PostgreSQL. It discusses: 1) PL/pgSQL allows writing procedures, functions, and triggers to extend PostgreSQL's functionality beyond standard SQL queries. This allows executing multiple statements together efficiently rather than individual queries. 2) Key advantages include reducing round trips between applications and the database server and avoiding transferring result sets. 3) PL/pgSQL code is organized into blocks, which can be anonymous or named functions and procedures. Variables are declared and used to store temporary data within blocks.

Uploaded by

Essadik Dev
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 77

ADVANCED DATABASES

GI: 2nd year


CONTENTS:
▪ Chapter I: Advanced SQL Language

▪ Chapter II: Procedural programming with SQL Language

▪ Chapter III: Databases administration

All SQL statements will be given according to postresql syntax

2
CHAPTER II
SQL Language: Procedural Mode
CONTENTS:
▪ PL/PgSQL language
▪ Stored procedures and functions
▪ Triggers
▪ Procedure grouping and packages

4
PL/PGSQL LANGUAGE: PROCEDURAL LANGUAGE OVERVIEW
▪ Queries and expressions in SQL are ideal for large set-at-a-time operations:
❖Operations that need to search the whole relation to answer a complex combination
of tuples.
❖Using SQL allows database to use the query optimizer to find the best query
execution plan for the query.
▪ However, SQL is not efficient for some programming tasks:
❖Sequence of code: A block of queries that must be executed in an order
❖Conditionals (if/then/else) statements (some simple ones can be handled, but
cannot be combined with sequence of code)
❖Loops
❖Storing values in and use values from program variables
❖Error handling

5
PL/PGSQL LANGUAGE: PROCEDURAL LANGUAGE OVERVIEW
▪ To enable the use of SQL for costly queries, while making it possible to write
code/procedures on top of it, databases support a number of options.
▪ The options belong in two main options:
❖ Server side
❖ Client side

Server side Client side


▪ Languages make it possible to define ▪ Languages allow programs to integrate
procedures, functions and triggers querying of the database with a procedural
▪ These programs are compiled and stored language
within the database server ▪ Coding in a host language with db hooks
▪ They can also be called by queries (C, C++, Java, Python, etc.) using the data
structures of these languages
▪ Coding in frameworks with their own data
models (Java, Python, etc) with similar db
hooks as in above.
6
PL/PGSQL LANGUAGE: PROCEDURAL LANGUAGE OVERVIEW
Programming with SQL
▪ All programming paradigms support:
❖ Methods to execute queries and update statements
❖ Executing any SQL statement and catching the outcome
❖ Interpret errors returned if any
❖ Input values from variables into queries, output query results into variables
❖ Loop over query results (for queries returning multiple tuples)
❖ Raise exceptions (which results in rollback of transactions)
❖ Store and reuse queries in the shape of cursors
❖ Starting and committing transactions

▪ Client side programs also support:


▪ Opening/closing connections, allocating/releasing database resources for queries

▪ The actual syntax of the methods for doing this vary, but the principle is the same.

7
PL/PGSQL LANGUAGE: PROCEDURAL LANGUAGE OVERVIEW
Server side language examples
▪ Generally database specific
▪ Postgresql:
▪ pl/pgsql: generic procedural language for postgresql
▪ pl/pyhton: procedural language that is an extension of python (also see pl/tcl, pl/perl)

8
PL/PGSQL LANGUAGE: PROCEDURAL LANGUAGE OVERVIEW
Client side language examples
▪ Database specific extensions of host languages, for example
▪ libpq: C library for postgresql, uses library calls for specific to postgresql
▪ OCCI: Oracle library for C

▪ Write code in C with hooks to the database in the form of functions and libraries, and
compile using C compiler
▪ ECPG: embedded programming in SQL, based on the embedded programming
standard with a postgresql specific pre-compiler, and the standard C compiler
▪ Standard libraries for connecting to the database
▪ JDBC is a Java standard library, all databases implement the same functions (some non-
standard data types will be different)
▪ To compile code with JDBC functions, the specific adapter (library) for a database must
be used.
▪ No specific standard for libraries based on C, but ODBC is a non-language specific
standard, .NET tries to achieve the same
▪ Python DB-API is a database independent framework for Python… 9
PL/PGSQL LANGUAGE: WHAT IS PL/PGSQL
▪ PL/pgSQL is a procedural programming language for the PostgreSQL database
system.
▪ PL/pgSQL allows you to extend the functionality of the PostgreSQL database server
by creating server objects with complex logic.
▪ PL/pgSQL was designed to :
❖Create user-defined functions, stored procedures, and triggers.
❖Extend standard SQL by adding control structures such as if, case, and loop statements.
❖Inherit all user-defined functions, operators, and types.

10
PL/PGSQL LANGUAGE: ADVANTAGES OF USING PL/PGSQL
▪ SQL is a query language that allows you to query data from the database easily.

Nonetheless, PostgreSQL can only process SQL statements on an individual basis.

▪ This implies that when you have multiple statements, you must execute them

sequentially, as shown below:


❖ First, send a query to the PostgreSQL database server.

❖ Next, wait for it to process.

❖ Then, process the result set.

❖ After that, do some calculations.

❖ Finally, send another query to the PostgreSQL database server and repeat this process.

11
PL/PGSQL LANGUAGE: ADVANTAGES OF USING PL/PGSQL
▪ This procedure results in the overhead of interprocess communication and network

operations.

▪ To resolve this issue, PostgreSQL uses PL/pgSQL.

▪ PL/pgSQL wraps multiple statements in an object and store it on the PostgreSQL

database server.

▪ So instead of sending multiple statements to the server one by one, you can send

one statement to execute the object stored in the server.

▪ This allows you to:

❖ Reduce the number of round trips between the application and the PostgreSQL database

server.
12
❖ Avoid transferring the immediate results between the application and the server.
PL/PGSQL LANGUAGE: PL/PGSQL ENVIRONEMENT
▪ The basic unit in any PL/pgSQL code is a
BLOCK.
▪ All PL/pgSQL code is composed of a single
block or blocks that occur either
sequentially or nested within another
block.
▪ There are two kinds of blocks:
❖ Anonymous blocks (DO): Generally
constructed dynamically and executed
only once by the user. It is sort of a
complex SQL statement.
❖ Named blocks (Functions and Stored
Procedures)
✓ Have a name associated with them,
✓ are stored in the database, and can
be executed repeatably, and can
take in parameters
13
PL/PGSQL LANGUAGE: STRUCTURE OF ANONYMOUS BLOCK
▪ The $$ symbol is used to define a dollar-quoted
string:
❖ a way to represent string literals in
PL/pgSQL code, and they are often used for
embedding SQL statements or other text
content within PL/pgSQL functions or
procedures.
❖ are useful because they allow you to
include single quotes and line breaks
within the string without needing to escape
them, making it easier to work with
complex text content, including SQL
queries, inside PL/pgSQL code.
14
PL/PGSQL LANGUAGE: COMMENT
▪ There are two types of comments in PL/pgSQL
❖ -- starts a comment that extends to the end of the line
❖ /* multi-line comments */
▪ Commenting is necessary to tell people what is intended and why it was done a
specific way.
▪ Lean towards providing more comments as a precaution.

15
PL/PGSQL LANGUAGE: VARIABLES
Variables are : Handling Variables

▪ Used for ▪ Variables declared in the declaration section


preceding a block are initialized to their default
❖ Temporary storage of data
values every time the block is entered, not only
❖ Manipulation of stored values
once per function call.
❖ Re-usability
▪ Variables in a declaration section can shadow
❖ Ease of maintenance
variables of the same name in an outer block. If the
▪ Declared in the declarative section within a outer block is named with a label, its variables are
block still available by specifying them as

last_name VARCHAR(15); <Label >. <varnam >

16
PL/PGSQL LANGUAGE: VARIABLES
Declarations:
▪ Syntax:
identifier [CONSTANT] datatype [NOT NULL] [:= | = | DEFAULT expr];
▪ Examples :
v_birthday DATE;
v_age INT NOT NULL := 21;
v_name VARCHAR(15) := 'Homer’;
v_magic CONSTANT NUMERIC := 42;
v_valid BOOLEAN DEFAULT TRUE;

17
PL/PGSQL LANGUAGE: VARIABLES
%TYPE: %ROWTYPE:
Declare variable according to : Declare a variable with the type of a ROW of a
▪ A database column definition table
▪ Another previously declared variable Syntax:
Syntax: identifier table%ROWTYPE;
identifier table.column_name%TYPE; ▪ Examples :
▪ Examples : v_user users%ROWTYPE;
V_email users.email%TYPE;
my_email V_email%TYPE :=
'[email protected]';

18
PL/PGSQL LANGUAGE: VARIABLES
Records :
▪ A record is a type of variable similar to ROWTYPE, but with no predefined
structure
▪ The actual structure of the record is created when the variable is first assigned
▪ A record is not a true data type, only a place holder
Syntax:
r RECORD;

19
PL/PGSQL LANGUAGE: VARIABLES
Variable Scope :
DO $$
DECLARE
quantity INTEGER := 30;
BEGIN
RAISE NOTICE 'Quantity here is %', quantity;
quantity := 50;
-- Create a subblock
DECLARE
quantity integer := 80;
BEGIN
RAISE NOTICE 'Quantity here is %', quantity;
END;
RAISE NOTICE 'Quantity here is %', quantity;
END
20
$$;
PL/PGSQL LANGUAGE: VARIABLES
Qualify an Identifier:
DO $$
<< mainblock >>
DECLARE
quantity integer := 30;
BEGIN
RAISE NOTICE 'Quantity here is %', quantity;
quantity := 50;
-- Create a subblock
DECLARE
quantity integer := 80;
BEGIN
RAISE NOTICE 'Quantity here is %', mainblock.quantity;
RAISE NOTICE 'Quantity here is %', quantity;
END;
RAISE NOTICE 'Quantity here is %', quantity;
END
21
$$;
PL/PGSQL LANGUAGE: VARIABLES
RAISE:
▪ Reports messages
▪ Can be seen by the client if the appropriate level is used
RAISE NOTICE 'Calling cs_create_job(%)', job_id;

Assigning Values
Use the assignment operator ( := or = )
DECLARE
last_name VARCHAR := 'Smith’;
date DATE;
BEGIN
last_name := lower(last_name);
date := to_date('2000-01-01', 'YYYY-MM-DD'); 22
PL/PGSQL LANGUAGE: INSTRUCTIONS
SELECT in PL/pgSQL:
▪ Retrieve data from the database with a SELECT statement
▪ Queries must return only one row
▪ INTO clause is required

DECLARE
v_first_name users.first_name%TYPE;
v_last_name users.last_name%TYPE;
BEGIN
SELECT first_name, last_name INTO v_first_name, v_last_name
FROM users
WHERE user_id = 1;
END

23
PL/PGSQL LANGUAGE: INSTRUCTIONS
INSERT / UPDATE / DELETE :
DECLARE
v_forum_name forums.name%TYPE := 'Hackers’;
BEGIN
INSERT INTO forums (name) VALUES (v_forum_name);
UPDATE forums
SET moderated = true
WHERE name = v_forum_name;
END

PERFORM
▪ Evaluate an expression or query but discard the result
▪ Frequently used when executing maintenance command

BEGIN
PERFORM create_partition('moderation_log', '2016-06’);
END

24
PL/PGSQL LANGUAGE: FUNCTIONS
Structure of Named Blocks :
▪ RETURNS define the return type of the function.
CREATE FUNCTION [ function_name ] (parameters_list) The return type can be an integer, string,
RETURNS [return_type] $$
query, table columns, etc. You can specify
[ < < label> > ]
DECLARE the void if there is no return type. RETURNS
/* Declare section (optional). */ can be skipped if the parameter list contains
BEGIN OUT or INOUT parameters.
/* Executable section (required). */
EXCEPTION ▪ LANGUAGE defines the language in which
/* Exception handling section (optional). */
function will be implemented.
END [ label ]
$$ LANGUAGE plpgsql
▪ The dollar quoted string constant ($$) specifies
the block.
25
PL/PGSQL LANGUAGE: FUNCTIONS
Example ▪ And a function that returns the number of users with a
specified number of gems
Let us define a users table:
CREATE TABLE users( CREATE or REPLACE FUNCTION users_count(number_of_gems int)
RETURNS int
id INT GENERATED BY DEFAULT AS LANGUAGE plpgsql
IDENTITY, AS
$$
name VARCHAR(50), DECLARE
gems DEC (10), user_count integer;
BEGIN
PRIMARY KEY (id)); SELECT count(*) INTO user_count
FROM users WHERE gems > number_of_gems;

RETURN user_count;
END;
We call this function with a simple SELECT $$;
statement:
SELECT users_count(1500); 26
PL/PGSQL LANGUAGE: FUNCTIONS
▪ To return a table from a function, use the following return statement inside the function,:
RETURNS table (column_list);
▪ The column_list contains specified columns from the list

▪ Let’s write a function that will return the user's id,


name, and gems.
CREATE or REPLACE FUNCTION users_gems() SELECT users_gems();
RETURNS table (id int,
name varchar,
gems DEC (10))
LANGUAGE plpgsql
AS
$$
BEGIN
RETURN query
SELECT * FROM users;

END;
$$; 27
PL/PGSQL LANGUAGE: FUNCTIONS
▪ The function accepts three types of parameters IN, OUT, and INOUT.
▪ The users_count() function has IN parameter and it is default type.
▪ The OUT and INOUT parameters should be explicitly mentioned like:
OUT parameter type
INOUT parameter type
▪ OUT parameter returns the output from the function and does not need to mention the RETURNS type
and return statement at the end of the block.
CREATE or REPLACE FUNCTION To get the output:
total_user_count(OUT user_count int)
LANGUAGE plpgsql SELECT total_user_count();
AS ▪ One or more parameters can be used.
$$ ▪ Parameter names are optional, but highly
BEGIN recommended .
SELECT count(*) INTO user_count
FROM users;

END;
$$;
28
PL/PGSQL LANGUAGE: FUNCTIONS
Default parameters:
▪ Paramters can have a default value
▪ This essentially makes them optional parameters
CREATE FUNCTION get_user_count(p_active boolean DEFAULT true)
RETURNS integer AS $$
DECLARE
v_count integer;
BEGIN
SELECT count(*) INTO v_count
FROM users
WHERE active = p_active;
RETURN v_count;
END
29
$$ LANGUAGE plpgsql;
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
▪ The sequence of instructions can be altered by incorporating conditional IF statements and loop control
structures

IF-Statemment: Nested IF Statements:


IF-THEN IF boolean-expression THEN
IF boolean-expression THEN IF boolean-expression THEN
statements statements
END IF; END IF;
ELSE
IF-THEN-ELSE statements
IF boolean-expression THEN END IF;
statements
ELSE
statements
END IF;

30
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
ELSIF Statements: A sequence of statements based on multiple conditions
IF number = 0 THEN
result := 'zero’;
ELSIF number > 0 THEN
result := 'positive’;
ELSIF number < 0 THEN
result := 'negative’;
ELSE
-- the only other possibility is that number is null
result := 'NULL’;
END IF; 31
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
CASE Statements:
Besides the if statement, PostgreSQL provides you with case statements that allow you to
execute a block of code based on a condition.
The case statement selects a when section to execute from a list of when sections based on a
condition.
The case statement has two forms:
▪ Simple case statement
▪ Searched case statement

32
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
CASE Statements:
The case statement compares the result of the search-expression with the expression in
each when branch using equal operator ( =) from top to bottom.

1) Simple case statement


case search-expression
when expression_1 [, expression_2, ...] then
when-statements
search-expression: an expression that evaluates to a
[ ... ]
result.
[else
else-statements ]
END case;

33
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
DO $$
DECLARE
rate film.rental_rate%TYPE;
price_segment VARCHAR(50);
BEGIN
SELECT rental_rate INTO rate -- get the rental rate
FROM film
WHERE film_id = 100;
-- assign the price segment
IF FOUND THEN
CASE rate
WHEN 0.99 THEN
price_segment = 'Mass';
WHEN 2.99 then
price_segment = 'Mainstream';
WHEN 4.99 then
price_segment = 'High End';
ELSE
price_segment = 'Unspecified';
END CASE;
RAISE NOTICE '%', price_segment;
END IF; 34
END; $$
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
2) Searched case statement

▪ In this syntax, the case statement evaluates the


Syntax
CASE boolean expressions sequentially from top to
WHEN boolean-expression-1 THEN bottom until it finds an expression that
statements
[ WHEN boolean-expression-2 THEN evaluates to true.
statements ▪ The ELSE section is optional.
... ]
[ ELSE ▪ If you omit the ELSE section and there is no
statements ] expression evaluates to TRUE, the CASE
END CASE;
statement will raise the CASE_NOT_FOUND
exception.

35
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
DO $$
DECLARE
total_payment NUMERIC;
service_level VARCHAR(25) ;
BEGIN
SELECT SUM(amount) INTO total_payment
FROM Payment
WHERE customer_id = 100;

IF FOUND THEN
CASE
When total_payment > 200 THEN
service_level = 'Platinum' ;
WHEN total_payment > 100 THEN
service_level = 'Gold' ;
ELSE
service_level = 'Silver’ ;
END CASE;
RAISE NOTICE 'Service Level: %', service_level;
ELSE
RAISE NOTICE 'Customer not found';
END IF; 36
END; $$
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
FOUND:
▪ In each PL/pgSQL function call, the initial state of the boolean variable FOUND is set to
FALSE.
▪ The boolean variable FOUND in PL/pgSQL is determined by the following types of
statements:
❖ When a SELECT INTO statement is executed, it sets FOUND to TRUE if it returns a row
and FALSE if no row is returned.
❖ A PERFORM statement sets FOUND to TRUE if it generates and discards a row, and
FALSE if no row is generated.
❖ UPDATE, INSERT, and DELETE statements set FOUND to TRUE if they affect at least
one row and FALSE if they have no impact on rows.
❖ For a FETCH statement, FOUND is set to TRUE when it retrieves a row and FALSE when
no row is retrieved.
❖ In the case of a FOR loop, FOUND is set to TRUE if the loop iterates one or more times;
otherwise, it is set to FALSE.

37
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
FOUND:
Example:
DECLARE
v_first_name users.first_name%TYPE;
v_last_name users.last_name%TYPE;
BEGIN
SELECT first_name, last_name INTO v_first_name, v_last_name
FROM users
WHERE user_id = 1;
IF FOUND THEN
RAISE NOTICE 'User Found’;
ELSE
RAISE NOTICE 'User Not Found’;
END IF;
END

38
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures :
There are several ways to implement loops in PostgreSQL:
▪ Unconstrained Loop
▪ WHILE Loop
▪ FOR Loop
▪ FOREACH Loop

39
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures : Unconstrained Loops
Enable the execution of its statements at least once, regardless of whether the condition has
already been satisfied when entering the loop

LOOP LOOP
-- some computations -- some computations
IF count > 0 THEN EXIT WHEN count > 0; -- same result as previous example
EXIT; -- exit loop END LOOP;
END IF;
END LOOP;

40
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures : Unconstrained Loops
CONTINUE:
CONTINUE [ label ] [ WHEN expression ];
Enable the execution of its statements at least once, regardless of whether the condition
has already been satisfied when entering the loop.
▪ When no label is provided, the innermost loop initiates the next iteration.
▪ If the WHEN condition is specified, the next iteration of the loop starts only if the
expression is true. Otherwise, control proceeds to the statement following the
CONTINUE statement.
▪ The CONTINUE statement can be applied to all types of loops; it is not restricted to
unconstrained loops.

41
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures : Unconstrained Loops
CONTINUE:
LOOP
-- some computations
EXIT WHEN count > 100;
CONTINUE WHEN count < 50;
-- some computations for count IN [50 .. 100]
END LOOP;

LOOP ▪ increments the result by 1 at each iteration as long as


resultat := resultat + 1; the result value is less than 50.
EXIT WHEN resultat > 100; ▪ The result is then incremented by 1 twice for each
CONTINUE WHEN resultat < 50; iteration of the loop. The result increases by 2 per
resultat := resultat + 1; loop
END LOOP; ▪ When 100 is reached, the program exits the loop

42
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures : WHILE Loops Example:
WHILE condition LOOP DO $$
statement1..; DECLARE
counter integer := 0;
END LOOP;
BEGIN
▪ Executes a series of statements
WHILE counter < 5 LOOP
repeatedly as long as the controlling RAISE NOTICE 'Counter %', counter;
condition remains TRUE. counter := counter + 1;
▪ The condition is evaluated at the start of END LOOP;
each iteration. END$$;

WHILE NOT done LOOP


-- some computations here
END LOOP;

43
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures: FOR Loops Example:
DO $$
FOR IN [REVERSE] .. LOOP [BY increment]
BEGIN
-- some computations here FOR i IN 1..10 LOOP
END LOOP; RAISE NOTICE 'value: %', i;
▪ Use a FOR loop to shortcut the test for the END LOOP;
number of iterations. END $$
▪ Do not declare the counter; it is declared
implicitly

44
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures: Looping Over Results (of a query)
For loops can directly use a query result: The last row is still accessible after exiting the
loop:
DECLARE DECLARE
r record; r record;
BEGIN
BEGIN FOR r IN SELECT email FROM users LOOP
FOR r IN SELECT email FROM users LOOP RAISE NOTICE 'Email: %', r.email;
END LOOP;
RAISE NOTICE 'Email: %', r.email; RAISE NOTICE 'Email: %', r.email;
END LOOP;
END;

45
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures: Looping Over Results Loop Structures: Looping Over Arrays
▪ Looping over dynamic SQL ▪ Uses the FOREACH statement
▪ Re-planned each time it is executed FOREACH variable [SLICE n] IN ARRAY expression

DECLARE LOOP … END LOOP ;

rec RECORD; ▪ To loop over the elements of an array, variable will

sql text; obtain the different values of the array returned by

BEGIN expression

sql := 'SELECT email FROM users’; ▪ SLICE can be used to control the number of array

FOR rec IN EXECUTE sql LOOP dimensions to be passed to the variable


RAISE NOTICE 'Email: %', rec.email; ▪ Label is optionnal
END LOOP;
END
46
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures: Looping Over Arrays
Example without SLICE:
DO $$
DECLARE
a int[] := ARRAY[[1,2],[3,4],[5,6]];
b int;
BEGIN
FOREACH b IN ARRAY a LOOP
RAISE INFO 'var: %', b;
END LOOP;
END $$ ;

47
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures: Looping Over Arrays
Example with SLICE:
Use the SLICE syntax to iterate over multiple dimensions
DO $$
DECLARE
users varchar[];
v_dim varchar[]; --must be an array type when using slice 1 or 2
BEGIN
users := ARRAY[ARRAY['Mickey', 'Donald'], ARRAY['Mouse', 'Duck']];
FOREACH v_dim SLICE 1 IN ARRAY users LOOP
RAISE NOTICE 'Dimension: %', v_dim;
END LOOP;
48
END; $$
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
Loop Structures: Looping Over Arrays
Example with SLICE:
Use the SLICE syntax to iterate over multiple dimensions
DECLARE
users varchar[];
v_dim varchar[];
BEGIN
users := ARRAY[ARRAY['Mickey', 'Donald'], ARRAY['Mouse', 'Duck']];
FOREACH v_dim SLICE 2 IN ARRAY users LOOP
RAISE NOTICE 'Dimension: %', v_dim;
END LOOP;
END;
49
PL/PGSQL LANGUAGE: CONTROL STRUCTURES
BEGIN
Loop Structures: Nested Loops < < Outer_loop > >
▪ Nest loops to multiple levels LOOP
▪ Use labels to distinguish between blocks v_counter := v_counter + 1;
▪ Exit the outer loop with the EXIT statement that EXIT WHEN v_counter > 10; -- leaves both loops
references the label < < Inner_loop > >
LOOP
EXIT Outer_loop WHEN total_done = 'YES’;
-- leaves both loops
EXIT WHEN inner_done = 'YES’;
-- leaves inner loop only
END LOOP Inner_loop;
END LOOP Outer_loop;
END; 50
PL/PGSQL LANGUAGE: EXAMPLE
CREATE OR REPLACE FUNCTION active_locks(OUT p_exclusive int, OUT p_share int) AS
$$ BEGIN
SELECT sum(CASE l.mode WHEN 'ExclusiveLock' THEN 1 ELSE 0 END),
sum(CASE l.mode WHEN 'ShareLock' THEN 1 ELSE 0 END)
INTO p_exclusive, p_share
FROM pg_locks l, pg_stat_activity a
WHERE a.pid = l.pid
AND a.usename = SESSION_USER;
END
$$ LANGUAGE plpgsql;

51
PL/PGSQL LANGUAGE: EXAMPLE
CREATE OR REPLACE FUNCTION active_locks(OUT p_exclusive int, OUT p_share int) AS
$$ BEGIN
SELECT sum(CASE l.mode WHEN 'ExclusiveLock' THEN 1 ELSE 0 END),
sum(CASE l.mode WHEN 'ShareLock' THEN 1 ELSE 0 END)
INTO p_exclusive, p_share
FROM pg_locks l, pg_stat_activity a
WHERE a.pid = l.pid
AND a.usename = SESSION_USER;
END
$$ LANGUAGE plpgsql;

52
PL/PGSQL LANGUAGE: CURSORS
▪ A PL/pgSQL cursor allows you to encapsulate a query and process each
individual row at a time.
▪ Cursors are typically employed when you need to segment a substantial result set
into smaller portions and handle each segment separately.
▪ Processing the entire set at once could lead to a memory overflow error.
▪ Additionally, you can develop a function that returns a reference to a cursor. This
is an effective way to return a large result set from a function. The caller of the
function can process the result set based on the cursor reference.

53
PL/PGSQL LANGUAGE: CURSORS
▪ Each SQL statement executed in PostgreSQL is linked to an individual cursor.
▪ Implicit cursors are automatically declared for all Data Manipulation Language
(DML) and PL/pgSQL SELECT statements.
▪ In contrast, explicit cursors are declared and given a specific name by the
programmer when needed.
▪ Utilize a CURSOR to individually handle and process each row obtained from a
multi-row SELECT statement.

54
PL/PGSQL LANGUAGE: CURSORS
Here's a simplified schema of cursor flow that provides an overview of how cursors are used to fetch
and process data from a result set in a structured way:
1.Cursor Declaration:
▪ Define and declare a cursor with a specific name and associate it with a SELECT statement.
▪ Optionally, you can specify the type of cursor, such as FORWARD-ONLY, SCROLL, etc.
2.Cursor Initialization:
▪ Open the cursor to establish a connection to the result set generated by the associated
SELECT statement.
▪ The cursor is positioned at the beginning of the result set.
3.Fetch Data:
▪ Use the FETCH command to retrieve rows from the result set one at a time or in a batch.
▪ Process the data retrieved from each fetch operation.
4.Iterate Over Result Set:
▪ Continue to fetch data in a loop until you have processed all the rows or met a specific
condition.

55
PL/PGSQL LANGUAGE: CURSORS
5.Cursor Termination:
▪ After all rows have been fetched and processed, close the cursor to release the
associated resources.
▪ Alternatively, the cursor may be closed in case of an error or when it's no longer
needed.
6.Optional Reuse:
▪ Depending on the cursor type, you may be able to reopen and reuse the cursor to
reiterate through the result set if necessary.
7.Clean-up and Deallocate:
▪ In some database systems, you may need to deallocate the cursor explicitly to free
up system resources.
The specific syntax and behavior of cursors may vary depending on the database
management system you are using.

56
PL/PGSQL LANGUAGE: CURSORS
+------------------+ +---------------+ +--------------+
| Cursor Declaration | -> | Cursor Open | -> | Fetch Data |
| (Specify SQL) | | (Execute) | | (Retrieve) |
+------------------+ +---------------+ +--------------+
|
|
v
+------------------+
| Data Processing |
| (Actions) |
+------------------+
|
|
v
+--------------+
| Cursor Close |
| (Release) |
+--------------+
|
|
v
+------------------+
| Error Handling |
| (Exceptions) |
+------------------+
|
|
v
+------------------+
| Looping/Iterating |
| (Repeat for Rows) |
+------------------+
|
|
v 57
(Back to "Fetch Data" for the next row)
PL/PGSQL LANGUAGE: DECLARING CURSORS

▪ A cursor must be declared as a variable


❖ Use the SCROLL keyword to move backwards through a cursor
name [ [ NO ] SCROLL ] CURSOR [ ( arguments ) ] FOR query;
DECLARE
curs1 refcursor;--A REF CURSOR, short for "reference cursor," is a pointer to a result set, typically used in
-- database procedures and functions to return query results.
curs2 CURSOR FOR SELECT * FROM tenk1;
curs3 CURSOR (key integer) FOR SELECT *
FROM tenk1
WHERE unique1 = key;

58
PL/PGSQL LANGUAGE: OPENING CURSORS

▪ The OPEN method to use is dependant on the way it was declared


OPEN curs1 FOR SELECT * FROM table WHERE key = mykey;
OPEN cur2;
OPEN curs3(42);
OPEN curs3 (key := 42);

59
PL/PGSQL LANGUAGE: FETCHING DATA

▪ FETCH returns the next row


FETCH curs2 INTO table.col1, table.clo2…;
▪ FETCH can also move around the cursor
FETCH LAST FROM curs3 INTO x, y;

60
PL/PGSQL LANGUAGE: FETCHING DATA
CREATE FUNCTION grant_select(p_role varchar) ▪ grant_select is used to grant
RETURNS void AS $$ SELECT privileges on all
DECLARE user tables in the
sql varchar; -- variable to store dynamic SQL statements PostgreSQL database to a
r record; -- record to hold data from the cursor specified role
tbl_cursor CURSOR FOR SELECT schemaname, relname ▪ tbl_cursor retrieves the
FROM pg_stat_user_tables; names of user tables
(schemaname and relname)
BEGIN
from the ‘pg_stat_user_tables’
OPEN tbl_cursor; system catalog
LOOP ▪ call this function and provide
FETCH tbl_cursor INTO r; the desired role as a
EXIT WHEN NOT FOUND; parameter to grant SELECT
sql := 'GRANT SELECT ON TABLE ' || r.schemaname || privileges on all user tables
'.' || r.relname || ' TO ' || p_role; SELECT
EXECUTE sql; grant_select('your_role_name');
END LOOP;
CLOSE tbl_cursor;
END
$$ LANGUAGE plpgsql;
61
PL/PGSQL LANGUAGE: IMPLICIT CURSOR
Full cursor path
CREATE OR REPLACE FUNCTION listeEmp() RETURNS SETOF tEmploye AS $$
DECLARE
ntuple emp%ROWTYPE;
e tEmploye;
BEGIN
FOR ntuple IN SELECT * FROM emp LOOP
e.num := ntuple.empno;
e.name := LOWER(ntuple.ename);
RETURN NEXT e;
END LOOP;
RETURN;
END
$$ LANGUAGE plpgsql;

SELECT listeEmp();
62
PL/PGSQL LANGUAGE: EXPLICIT CURSOR
Ad-hoc cursor path (same result as listeEmp → use listeEmp !!)
CREATE OR REPLACE FUNCTION listeEmp2() RETURNS SETOF tEmploye AS $$ ▪ returns a set of
DECLARE records of the type
cursEmp CURSOR FOR SELECT * FROM emp; ‘tEmploye’ from the
ntuple emp%ROWTYPE; ‘emp’ table.
e tEmploye; ▪ It uses a cursor to
BEGIN fetch records from
OPEN cursEmp; the emp table,
FETCH cursEmp INTO ntuple; -- Read 1st n-tuple transforms the data,
WHILE FOUND LOOP and returns the
e.num := ntuple.empno; result as a set of
e.name := LOWER(ntuple.ename); tEmploye records
RETURN NEXT e;
FETCH cursEmp INTO ntuple; -- Read next n-tuple
END LOOP;
CLOSE cursEmp;
RETURN;
END
$$ LANGUAGE plpgsql;
63
PL/PGSQL LANGUAGE: EXPLICIT CURSOR
Truly ad-hoc cursor path (returns 1 result out of 3)
CREATE OR REPLACE FUNCTION listeEmp3(step INT) RETURNS SETOF tEmploye AS $$
DECLARE -- Same declarations
BEGIN
OPEN cursEmp;
FETCH cursEmp INTO ntuple;
WHILE FOUND LOOP
e.num := ntuple.empno;
e.name := LOWER(nuplet.ename);
RETURN NEXT e;
MOVE FORWARD step FROM cursEmp; -- MOVE cursEmp; for a single step
FETCH cursEmp INTO ntuple;
END LOOP;
CLOSE cursEmp;
RETURN;
END
$$ LANGUAGE plpgsql;

SELECT * FROM listeEmp3(2); 64


PL/PGSQL LANGUAGE: EXPLICIT CURSOR (PARAMETERIZED CURSOR)
CREATE OR REPLACE FUNCTION listeEmp4(salPlancher DECIMAL) RETURNS SETOF tEmploye AS $$
DECLARE
cursEmp CURSOR(salMin DECIMAL) FOR SELECT * FROM emp WHERE sal >= salMin;
ntuple emp%ROWTYPE;
e tEmploye;
BEGIN
OPEN cursEmp(salPlancher);
FETCH cursEmp INTO ntuple; It can be written in a much simpler
WHILE FOUND LOOP way
e.num := ntuple.empno;
e.name := LOWER(ntuple.ename);
RETURN NEXT e;
FETCH cursEmp INTO ntuple;
END LOOP;
CLOSE cursEmp;
RETURN;
END
$$ LANGUAGE plpgsql;

SELECT listeEmp4(2000); 65
PL/PGSQL LANGUAGE: IMPLICIT CURSOR
Simpler and more easily readable
CREATE OR REPLACE FUNCTION listeEmp5(salPlancher DECIMAL) RETURNS SETOF
tEmploye AS $$
DECLARE
ntuple emp%ROWTYPE;
e tEmploye;
BEGIN
FOR ntuple IN SELECT * FROM emp WHERE sal >= salPlancher LOOP
e.num := ntuple.empno;
e.name := LOWER(ntuple.ename);
RETURN NEXT e;
END LOOP;
RETURN;
END
$$ LANGUAGE plpgsql;

SELECT listeEmp5(2000);
66
PL/PGSQL LANGUAGE: TRIGGERS

▪ A trigger specifies that the database must automatically execute a given function every
time a certain type of operation is performed.
▪ Trigger functions can be attached to a table, a view, or a remote table.

67
PL/PGSQL LANGUAGE: MAIN TRIGGER TYPES

INSERT DELETE UPDATE


BEFORE 1 2 3
AFTER 4 5 6

68
PL/PGSQL LANGUAGE: TRIGGER CREATION/DELETION

Syntax:
CREATE TRIGGER trigName
BEFORE | AFTER
INSERT | DELETE | UPDATE | [INSERT] [[OR] DELETE] [[OR] UPDATE]
ON tableName FOR EACH ROW | FOR EACH STATEMENT
EXECUTE PROCEDURE functionName();
DROP TRIGGER trigName
ON tableName;

69
PL/PGSQL LANGUAGE: TRIGGER SYSTEM VARIABLES

NEW : Record containing the inserted or modified tuple


Example:
INSERT INTO customers VALUES (1, ‘NewCostumer’);
NEW.NumCli takes the value 1 in a customer trigger.
NEW.Name takes the value 'NewCustomer' in the trigger.
OLD : Record containing old tuple deleted or modified
Example:
DELETE FROM customers WHERE NumCli = 33;
OLD.NumCli takes the value 33 in the trigger.

70
PL/PGSQL LANGUAGE: TRIGGERS: EXAMPLES
Primary key emulation on Employee table
CREATE OR REPLACE FUNCTION checkEmpPK() RETURNS TRIGGER AS $$
DECLARE
n INTEGER;
BEGIN
--primary key is null?
IF NEW.empno IS NULL THEN
RAISE EXCEPTION ' The primary key must have a value! ';
END IF;
-- Does the key already exist?
SELECT COUNT(empno) INTO n FROM emp
WHERE empno = NEW.empno;
IF n > 0 THEN
RAISE EXCEPTION ‘primarykey already used !’;
END IF;
RETURN NEW; CREATE TRIGGER trigEmpPK
END BEFORE INSERT OR UPDATE ON emp FOR EACH
$$ LANGUAGE plpgsql; ROW EXECUTE PROCEDURE checkEmpPK(); 71
PL/PGSQL LANGUAGE: STATIC SQL VS. DYNAMIC SQL

▪ Function that updates the employee table (e.g. salary change)⇒ Static
SQL (the query is known at compile time)
▪ Function that updates a table whose name is a parameter ⇒ Dynamic
SQL (the complete query is not known at compile time)
▪ Dynamic SQL refers to the practice of constructing SQL queries as
strings at runtime, and then executing those queries within a program or
script. This is in contrast to static SQL, where the SQL queries are pre-
defined and known at compile time. Dynamic SQL allows you to build
SQL statements on the fly based on the specific conditions or
requirements of your program.
72
PL/PGSQL LANGUAGE: DYNAMIC QUERIES

▪ Execution:
EXECUTE query [INTO result];
❖ query is a character string
❖ result is a variable, a set of variables or a record
▪ Note :
❖ Parameterized query: database values → static query
❖ If you want to parameterize objects (tables, views, attributes...) → dynamic
query

73
PL/PGSQL LANGUAGE: EXAMPLE OF A DYNAMIC QUERY
CREATE OR REPLACE FUNCTION tableSize(tableName VARCHAR)
RETURNS INTEGER AS $$
DECLARE
n INTEGER;
BEGIN
EXECUTE 'SELECT COUNT(*) FROM ' || tableName INTO n;
RETURN n;
END
$$ LANGUAGE plpgsql;

SELECT tableSize('EMP');
74
PL/PGSQL LANGUAGE: DYNAMIC CURSORS (1/2)
CREATE OR REPLACE FUNCTION tablepath(tableName VARCHAR) RETURNS VOID AS $$
DECLARE
dynCurs REFCURSOR;
ntuple RECORD;
BEGIN
OPEN dynCurs FOR EXECUTE 'SELECT * FROM ' || tableName;
FETCH dynCurs INTO ntuple;
WHILE FOUND LOOP
-- Operations on ntuple
FETCH dynCurs INTO ntuple;
END LOOP;
CLOSE dynCurs;
END
$$ LANGUAGE plpgsql;

SELECT tablepath('EMP’);

75
PL/PGSQL LANGUAGE: DYNAMIC CURSORS (2/2)
CREATE FUNCTION tableContent(tableName VARCHAR, nameID VARCHAR)
RETURNS SETOF VARCHAR AS $$
DECLARE
dynCurs REFCURSOR;
id VARCHAR;
BEGIN
OPEN dynCurs FOR EXECUTE 'SELECT ' || nameID || ' FROM ' || tableName;
FETCH dynCurs INTO id;
WHILE FOUND LOOP
RETURN NEXT id;
FETCH dynCurs INTO id;
END LOOP;
CLOSE dynCurs;
RETURN;
END
$$ LANGUAGE plpgsql;

SELECT tableContent('EMP', 'EMPNO'); 76

You might also like