2. Introduzione al PL/SQL per Oracle - I fondamentali
• Linguaggio procedurale che integra ed estende l’ SQL
standard
• E’ di fatto proprietario di Oracle Corporation. Non esiste
nessuno standard per PL/SQL ma ANSI ci sta lavorando.
• Basato sui concetti di programmazione ADA.
• Inizialmente forniva logiche di batch-processing per script
SQL
• Poi, è diventato un vero e proprio ambiente di
programmazione.
L’acronimo: Procedural Language SQL
3. PL/SQL - I fondamentali
Una buona strada per cominciare ad esplorare il PL/SQL è cominciare
da un esempio:
• Il programma, elabora gli ordini per delle racchette da tennis
verificandone la quantità disponibile ad inventario
• Dichiara una variabile di tipo NUMBER per mantenere la quantità di
racchette a disposizione
• Recupera questo valore dalla tavola “inventario” del db
• Se la quantità è >0 il programma modifica la tavola ed inserisce
un nuovo record nella tabella “ordini”
• Altrimenti, il programma evidenzia un record di “esaurito” nella
tabella “ordini”
4. PL/SQL - I fondamentali
DECLARE
qta_disp NUMBER(5);
BEGIN
SELECT quantita INTO qta_disp FROM inventario
WHERE prodotto LIKE ’TENNIS RACKET’ FOR UPDATE OF quantita;
IF qta_disp > 0 THEN
UPDATE inventario SET quantita=quantita - 1
WHERE prodotto LIKE ’TENNIS RACKET’;
INSERT INTO ordini
VALUES (’Racchetta da Tennis ordinata’, SYSDATE);
ELSE
INSERT INTO ordini
VALUES (’Racchette da Tennis Esaurite!’, SYSDATE);
END IF;
COMMIT;
END;
5. PL/SQL - I fondamentali
• Con PL/SQL è possibile adoperare gli statement SQL per
manipolare dati nel db in abbinamento al controllo di flusso di un
ambiente di programmazione
• E’ possibile dichiarare variabili di programma, costanti, definire
procedure, definire funzioni e gestire errori di run-time (eccezioni)
In definitiva PL/SQL combina la potenza interattiva della
manipolazione dei dati attraverso SQL con la potenza
del data processing dei linguaggi procedurali
6. PL/SQL - I fondamentali
STRUTTURA a BLOCCHI
PL/SQL è un linguaggio block-structured
• Le unità fondamentali (procedure, funzioni, e blocchi generici) che
costituiscono un programma PL/SQL equivalgono a blocchi logici
che possono contenere un qualsiasi numero di sotto-blocchi
annidati
• Tipicamente, ogni blocco logico corrisponde ad un problema o
sotto-problema da risolvere (dividi e conquista)
• Un blocco (o sotto-blocco) consente di raggruppare logicamente
dichiarazioni e statement correlati
• Le dichiarazioni sono locali al blocco in cui sono definite e cessano
di esistere quando il blocco termina
• Un blocco PL/SQL ha tre parti:
una parte dichiarativa (opzionale)
una parte di esecuzione
una parte di gestione delle eccezioni (opzionale)
7. PL/SQL - I fondamentali
I BLOCCHI
• Osservano una struttura di base
• Due tipi di blocchi: named and anonymous
• I named blocks sono functions and procedures
• Quattro sessioni in un blocco:
Header (rilevante solo per procedures and functions)
Declaration (opzionale)
Execution (sempre)
Exception (opzionale)
• I blocchi definiscono lo scope per le variabili e la gestione delle
eccezioni
• Vale l’annidamento !
9. PL/SQL - I fondamentali
STRUTTURA a BLOCCHI
• Solo oggetti dichiarati nella prima parte possono essere adoperati
nella fase di esecuzione
• Le eccezioni (runtime error + warning) scatenate nella fase di
esecuzione sono essere gestite dalla parte di exception handling
• All’interno delle parti di esecuzione e di gestione eccezioni è
possibile annidare altri blocchi
• Possono essere definiti dei sottoprogrammi nella fase dichiarativa,
tuttavia questi sono locali sola al blocco dove sono definiti
[DECLARE
---- dichiarazioni ]
BEGIN
------
statements
[EXCEPTION
---handlers ]
END;
10. PL/SQL - I fondamentali
DICHIARAZIONE di VARIABILI
Le variabili possono avere tipi di dato nativi SQL
(CHAR, DATE, NUMBER, ecc.)
Anche tipi di dato PL/SQL (BOOLEAN, REAL, BINARY_INTEGER, ecc.)
Esempi di dichiarazione
codice_articolo NUMBER(4);
art_presente BOOLEAN;
E’ possibile dichiarare anche tipi di dato più strutturati
TABLE (tabelle annidate)
VARRAY (array a lunghezza variabile)
RECORD (tipo di dato composto) tipico nell’uso dei cursori
11. PL/SQL - I fondamentali
ASSEGNAZIONE di Valori a Variabili
• Adoperando l’operatore di assegnamento (:=)
tax := price * tax_rate;
bonus := current_salary * 0.10;
amount := TO_NUMBER(SUBSTR(’750 dollars’, 1, 3));
valid := FALSE;
• Assegnando valori provenienti da select (fetch) sul database
• Calcolo del bonus come 10% del salario di un impiegato:
SELECT sal * 0.10 INTO bonus FROM emp WHERE
empno = emp_id;
• Il valore può essere adoperato in altri calcoli o per futuri
inserimenti a db
DICHIARAZIONE di COSTANTI
• Come per le variabili ma con la parola chiave CONSTANT e
con l’immediata assegnazione di un valore alla costante.
• Da qui in poi tale valore rimarrà inalterato
credit_limit CONSTANT REAL := 5000.00;
12. PL/SQL - I fondamentali
CURSORI e VARIABILI CURSORE
• Dei CURSOR e della loro definizione ed utilizzo abbiamo già visto
• Come un cursore, una variabile cursore punta alla riga corrente di un result
set ottenuto da query multirow
• Ma può essere aperta dinamicamente per ogni tipo di query compatibile
• Non è necessario specificare una query: le variabili cursore sono variabili
PL/SQL ! (Vale l’assegnamento, il passaggio di parametri, ecc.)
• La procedura seguente apre una variabile cursore “generic_cv” per una
query prescelta
PROCEDURE open_cv (generic_cv IN OUT GenericCurTyp, choice IN NUMBER)
IS
BEGIN
IF choice = 1 THEN
OPEN generic_cv FOR SELECT * FROM emp;
ELSIF choice = 2 THEN
OPEN generic_cv FOR SELECT * FROM dept;
ELSIF choice = 3 THEN
OPEN generic_cv FOR SELECT * FROM salgrade;
END IF;
13. PL/SQL - I fondamentali
ATTRIBUTI
• Varibili e cursori PL/SQL hanno attributi
• Sono proprietà che consentono di referenziare datatype e struttura di
oggetti senza doverne ripetere la loro definizione
• Colonne e tavole del db hanno attributi simili per la gestione
• Il segno di (%) è l’indicatore di attributo
%TYPE
• L’attributo %TYPE fornisce il datatype di una variabile o colonna di db
• Utile per dichiarare variabili che manterranno valori dal db
• Per esempio, se esiste una colonna “titolo” in una tavola “libri”, potrebbe
servire dichiarare una variabile “mio_titolo” dello stesso tipo di quella
colonna
mio_titolo libri.titolo%TYPE;
• Vantaggi
conoscere l’esatto tipo di dato del titolo
se cambia la definizione a db del campo titolo, la mia variabile cambia
a runtime
14. PL/SQL - I fondamentali
ATTRIBUTI
%ROWTYPE
• In PL/SQL, i record sono adoperati per mantenere valori di
dati provenienti da campi
• L’attributo %ROWTYPE fornisce un record type che
rappresenta una riga di una tavola
• Il record può mantenere righe di dati selezionate da tavole o
caricate da cursori
• Le colonne di una riga ed i corrispondenti campi di un record
hanno gli stessi datatypes.
• Nel primo esempio, si dichiara un record con nome
dept_rec, i suoi campi avranno lo stesso nome e lo stesso
tipo di dato delle colonne di dept
• Il secondo esempio è combinato con l’utilizzo dei cursori
15. PL/SQL - I fondamentali
ATTRIBUTI
%ROWTYPE
• Esempio 1:
DECLARE
dept_rec dept%ROWTYPE;
Adoperare la dot notation per riferire i singoli campi:
my_deptno := dept_rec.deptno;
• Esempio 2:
DECLARE
CURSOR c1 IS SELECT ename, sal, hiredate, job FROM emp;
emp_rec c1%ROWTYPE;
Quando si adopererà lo statement:
FETCH c1 INTO emp_rec;
avremo la sostituzione dei valori
16. PL/SQL - Strutture di controllo
Rappresentano il “gap” semantico del passaggio
SQL --> PL/SQL
Fino a qui, nella fase di esecuzione di un blocco PL/SQL,
abbiamo visto come trattare singoli statement sequenziali
Le strutture di controllo sono le vere e proprie strutture del
linguaggio che servono a governare ed a condizionare il flusso
di elaborazione sui dati
Le principali (in quasi tutti i linguaggi) sono:
IF-THEN-ELSE
FOR-LOOP
WHILE-LOOP
EXIT-WHEN
GOTO
17. PL/SQL - Strutture di controllo
Il Controllo CONDIZIONALE
• Azioni alternative dipendenti da specifiche circostanze
• Lo statement IF-THEN-ELSE permette di eseguire
blocchi di statement in modo condizionale
• La clausola IF verifica una condizione
• il ramo THEN definisce cosa fare quando la condizione
è vera
• il ramo ELSE cosa fare quando è falsa
18. PL/SQL - Strutture di controllo
Il Controllo CONDIZIONALE
DECLARE
acct_balance NUMBER(11,2);
acct CONSTANT NUMBER(4) := 3;
debit_amt CONSTANT NUMBER(5,2) := 500.00;
BEGIN
SELECT bal INTO acct_balance FROM accounts
WHERE account_id = acct
FOR UPDATE OF bal;
IF acct_balance >= debit_amt THEN
UPDATE accounts SET bal = bal - debit_amt WHERE account_id = acct;
ELSE
INSERT INTO temp VALUES (acct, acct_balance, ’Insufficient funds’);
END IF;
COMMIT;
END;
19. PL/SQL - Strutture di controllo
L’ITERAZIONE
Lo statement di LOOP permette di eseguire un blocco di
istruzioni più volte (ciclo)
La parola chiave LOOP anticipa il primo statement da ripetere
La parola chiave END LOOP chiude il blocco di istruzioni
ripetute
Il FOR-LOOP è un loop particolare definito da range di interi
FOR i IN 1..order_qty LOOP
UPDATE sales SET custno = customer_id
WHERE serial_num = serial_num_seq.NEXTVAL;
END LOOP;
Il WHILE-LOOP associa una condizione di ingresso per la
ripetizione del ciclo. La condizione viene valutata sempre
prima dell’esecuzione del ciclo ed il TRUE è il valore di
ingresso nel loop. Il loop viene saltato se la condizione è
FALSE o NULL, ed il controllo passa allo statement successivo
20. PL/SQL - Strutture di controllo
L’ITERAZIONE
• Esempio: trovare il primo impiegato che ha un salario > 4000 $ ed
il suo manager a partire dalla matricola 7902:
DECLARE
salary emp.sal%TYPE;
mgr_num emp.mgr%TYPE;
last_name emp.ename%TYPE;
starting_empno CONSTANT NUMBER(4) := 7902;
BEGIN
SELECT sal, mgr INTO salary, mgr_num FROM emp WHERE empno =
starting_empno;
WHILE salary < 4000 LOOP
SELECT sal, mgr, ename INTO salary, mgr_num, last_name
FROM emp WHERE empno = mgr_num;
END LOOP;
INSERT INTO temp VALUES (NULL, salary, last_name);
COMMIT;
END;
21. PL/SQL - Strutture di controllo
L’ITERAZIONE
• Lo statement EXIT-WHEN permette l’uscita anticipata
dal loop quando l’elaborazione successiva non è
desiderata
• Quando il programma incontra EXIT, la condizione
nella clausola WHEN viene valutata. Se TRUE, il loop
termina ed il controlla passa allo statement successivo
• Esempio: il ciclo termina quando il valore total supera
25000 $:
LOOP
...
total := total + salary;
EXIT WHEN total > 25000; -- esce dal loop se la condizione è
true
END LOOP;
-- il controllo di flusso prosegue qui
22. PL/SQL - Strutture di controllo
Il SALTO INCONDIZIONATO
• Lo statement GOTO consente di saltare in modo
incondizionato ad un punto preciso del programma
identificato da una label
• La label (etichetta) è un identificatore non dichiarato e
deve precedere uno statement o un blocco PL/SQL
• Viene esplicitata con la dicitura <<label>> :
IF rating > 90 THEN
GOTO calc_raise; -- salto alla label
END IF;
...
<<calc_raise>>
IF job_title = ’SALESMAN’ THEN -- il programma continua da qui
amount := commission * 0.25;
ELSE
amount := salary * 0.10;
END IF;
23. PL/SQL - Modularità
In PL/SQL è possibile definire strutture di
programma più semplici da richiamare in modo
modulare
VANTAGGI:
Strutturazione di un problema in problemi più semplici (divide et
impera)
Modularità
Ripetitività e riuso del codice sotto diverse premesse
Migliore gestione dell’applicazione
Semplicità di definizione e di implementazione
Si organizzano in:
• Sottoprogrammi
Procedure
Funzioni
• Procedure esterne
• Packages
24. PL/SQL - Modularità
PROCEDURE e FUNZIONI
• Sono blocchi di programma (subprogram) che prendono parametri e che
possono essere invocati (chiamati) da blocchi esterni
• Un subprogram è come un programma in miniatura che inizia con un
header, seguito da una parte dichiarativa opzionale, una parte di
esecuzione, e una sezione opzionale di exception-handling
PROCEDURE award_bonus (emp_id NUMBER) IS
bonus REAL;
comm_missing EXCEPTION;
BEGIN
SELECT comm * 0.15 INTO bonus FROM emp WHERE empno = emp_id;
IF bonus IS NULL THEN
RAISE comm_missing;
ELSE
UPDATE payroll SET pay = pay + bonus WHERE empno = emp_id;
END IF;
EXCEPTION
WHEN comm_missing THEN
...
END award_bonus;
25. PL/SQL - Modularità
PROCEDURE e FUNZIONI
Alla sua invocazione, questa procedura accetta il valore di una
matricola
Usa questo valore per selezionarne la commissione e per calcolarne un
bonus del 15%
Un successivo controllo sul bonus innalza un’eccezione se questo è
null, altrimenti il payroll dell’impiegato viene modificato
• La PROCEDURE non restituisce alcun valore
• La FUNCTION può restituire valori
CREATE FUNCTION interpolazione(x FLOAT, y FLOAT)
RETURN FLOAT AS EXTERNAL
LIBRARY mathlib
NAME "c_interp"
LANGUAGE C;
• L’esempio di funzione richiama un programma (procedura) esterno
la routine è definita in un linguaggio di più basso livello (C)
occorre includere la libreria di definizione della routine
(mathlib)
26. PL/SQL - Modularità
PACKAGES
• PL/SQL permette di raggruppare logicamente tipi,
variabili, cursori e sottoprogrammi in un package
• Sono semplici da capire e le loro interfacce sono
semplici chiare e ben definite
• I package aiutano lo sviluppo di applicazioni
• Realizzano astrazione del codice ed incapsulamento
• Package si costituiscono di due parti:
la specifica del package
il corpo de package (body)
• La specifica è l’interfaccia in cui si dichiarano: tipi,
costanti, variabili, exceptions, cursori, e
sottoprogrammi disponibili all’uso dell’applicativo
• Il body è l’implementazione della specifica; definisce
cursori e sottoprogrammi
27. PL/SQL - Modularità
PACKAGES
L’esempio raccoglie due procedure:
CREATE PACKAGE emp_actions AS -- specifica del package
PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...);
PROCEDURE fire_employee (emp_id NUMBER);
END emp_actions;
CREATE PACKAGE BODY emp_actions AS -- package body
PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...) IS
BEGIN
INSERT INTO emp VALUES (empno, ename, ...);
END hire_employee;
PROCEDURE fire_employee (emp_id NUMBER) IS
BEGIN
DELETE FROM emp WHERE empno = emp_id;
END fire_employee;
END emp_actions;
28. PL/SQL - Modularità
PACKAGES
• Solo le dichiarazioni effettuate nella specifica del
package sono accessibili dall’applicazione
• Il dettaglio di implementazione del body è nascosto ed
inaccessibile
• I package possono essere compilati e mantenuti dal
database dove il loro contenuto può essere reso
disponibile a diverse applicazioni
• Alla prima chiamata fatta su di un oggetto del
package, l’intero package viene caricato in memoria
• Le successive chiamate non fanno I/O a disco
• I package aumentano la produttività e migliorano le
performance del sistema
29. PL/SQL - Tipi di dato Astratto
Sono tipi di dato più complessi di quelli primitivi:
• COLLECTIONS: gruppo ordinato di elementi tutti dello stesso tipo,
corrispondono agli array dei linguaggi di terza generazione.
L’elemento corrente viene riferito da un indice
TABLE
VARRAY
• RECORD: aggregazione di campi di tipo diverso sotto un unico nome. Sono
adoperati dal %ROWTYPE, dai cursori, ma anche nelle esplicite definizione
di record dall’utente
DECLARE
TYPE TimeRec IS RECORD (minutes SMALLINT, hours SMALLINT);
TYPE MeetingTyp IS RECORD (
day DATE,
time TimeRec, -- record annidato
place VARCHAR2(20),
purpose VARCHAR2(50));
• OBJECT: incapsulamento di strutture dati complesse. Applicazione
della metodologia OO con definizione di strutture e metodi
30. PL/SQL - Gestione delle Eccezioni
• PL/SQL consente di rilevare e gestire eccezioni
• E’ il verificarsi a runtime di errori di programma o
warning
• Gestione del caso --> viene innalzata un’eccezione
• L’esecuzione normale termina ed il controllo del
programma viene trasferito alla sezione di exception-
handling del blocco PL/SQL
• Gli exception handlers sono le particolari routine
scritte per gestire le eccezioni
• Ne esistono di predefinite innalzate implicitamente dal
sistema (se divido un numero per zero, PL/SQL innalza
uno ZERO_DIVIDE in automatico)
• Le eccezioni definite dall’utente si devono innalzare
con lo statement RAISE
Le eccezioni vengono definite nella parte dichiarativa del blocco
PL/SQL (o di un subprogram)
Nella parte di esecuzione si controlla la condizione che
31. PL/SQL - Gestione delle Eccezioni
• L’esempio calcola il bonus posseduto da un venditore
• Il bonus si basa sul salario e sulla commissione per
cui, se la commissione è null, viene innalzata
un’eccezione di comm_missing.
DECLARE
...
comm_missing EXCEPTION; -- dichiarazione
BEGIN
...
IF commission IS NULL THEN
RAISE comm_missing; -- raise dell’eccezione
ELSE
bonus := (salary * 0.10) + (commission * 0.15);
END IF;
EXCEPTION
WHEN comm_missing THEN
-- codice per la cgestione dell’errore
32. PL/SQL - Architetture
Il sistema di runtime PL/SQL è una tecnologia
NON un prodotto
E’ un motore che esegue blocchi PL/SQL
Può essere installato indipendentmente su due tipi
di ambiente
• Oracle server
• Tools come Oracle Forms or Oracle Reports
In entrambi i casi il PL/SQL engine accetta in input
blocchi PL/SQL validi
Esempio di lavoro del motore PL/SQL
NB: Le istruzioni puro SQL
vengono eseguite dal db !
33. PL/SQL - Architetture
Metodi di esecuzione
• Oracle Server PL/SQL Engine
Anonymous Blocks: da tool interattivi come SQL*Plus o OEM
Stored Subprograms: procedure compilate separatamente e
mantenute permanentemente nel db. Una procedura
debitamente creata con CREATE è detta stored procedure. A
tutti gli effetti diventa un oggetto del data dctionary. Posso
richiamarli da trigger, altri stored subprogram, applicazioni
Oracle Precompilate, OCI application, o interattivamente da
SQL*Plus o Enterprise Manager. ES:
SQL> EXECUTE create_dept(’FINANCE’, ’NEW YORK’);
Database Triggers: procedura associata ad una tavola e a degli
eventi
• In Oracle Tools
se dispone di un motore PL/SQL, un ambiente di sviluppo può
elaborare blocchi PL/SQL
il tool passerà al db le sole chiamate relative alla elaborazione
di statement SQL
34. PL/SQL - Esempio di Procedura con
tutte e 4 le sessioni
PROCEDURE set_sales
(company_id_in IN NUMBER,
sales_in IN NUMBER,
calc_type_in IN VARCHAR2)
IS
sales_amt NUMBER;
upper_type VARCHAR2(30)
:= UPPER (calc_type_in);
BEGIN
IF upper_type = ‘ALL’
THEN
update_company
(company_id_in, sales_in);
END IF;
EXCEPTION
WHEN DIVIDE_BY_ZERO
THEN
display_error;
END;
Header
Execution
Declaration
Exception
35. PL/SQL - Esempio di Anonymous
Execution
Only
DECLARE
emp_name emp.ename%TYPE;
total_salary NUMBER;
invalid_employee EXCEPTION;
BEGIN
total_salary :=
get_sal (emp_name, ‘TOTAL’);
IF total_salary IS NULL
THEN
RAISE invalid_employee;
ELSE
DBMS_OUTPUT.PUT_LINE
(‘Total salary is ‘ ||
TO_CHAR (total_salary));
END IF;
EXCEPTION
WHEN invalid_employee
THEN
...
END;
Exception
Declaration
Execution
36. PL/SQL - Annidamento
E’ possibile
inscatolare un
anonymous block
dentro le sezioni di
execution and
exception di un altro
blocco PL/SQL
PROCEDURE ...
BEGIN
DECLARE
BEGIN
END;
EXCEPTION
WHEN ...
THEN
BEGIN
END;
END;
• Il blocco annidato ha la medesima struttura di quello che lo
rachiude
• Importante ! Ha le sue sezioni di declaration ed exception.
Occhio allo scope delle variabili
37. PL/SQL - Esempio di Annidamento
DECLARE
<declarations>
BEGIN
DECLARE
<declarations>
BEGIN
<executable statements>
END;
BEGIN
<executable statements>
EXCEPTION
<exception handlers>
END;
EXCEPTION
<exception handlers>
END;
Inner Block 1
Inner Block 2
38. PL/SQL - Nota sulla Sintassi
• Identificatori --> nomi per cose !
• Fino a 30 caratteri
• Devono iniziare con una lettera
• Valgono: “_”, “$”, “#” come separatori
• Si riconoscono identificatori con nomi di
program, loop, o package.
• La logica di statement termina con semi-colon
“;”
• Statements possono essere su più righe senza
continuation char
• Non case-sensitive, eccetto in caso di valori
string (come SQL)
39. PL/SQL - Esempi di Identificatori
I seguenti identificatori sono la stessa
cosa:
TOTAL_sales
TOTAL_SALES
total_sales
I seguenti sono illegali:
1st_year_total
company-name
match_found?
the_long_name_of_the_corporation
I seguenti sono OK:
row#
total_sales_$
First_year_total
40. PL/SQL - Identificatori - Tips (1)
Rendere i nomi sia comprensibili che
facilmente “riferibili”
Troppo “Criptici” !
totnumcomps
yrind
i j k x y
Troppo verbali !
total_number_companies
fiscal_year_index_number
Right !
total_companies
year_index
41. PL/SQL - Identificatori - Tips (2)
• Adottare un naming convenzionale nello sviluppo delle
applicazioni
• Prefissi e suffissi standard per cursori e nomi di record, ecc
• Permettere differenti variazioni per lo stesso identificatore
non serve a nulla in particolare
• Anche se per differenti programmi, non c’è nessuna
ragione per avere abbreviazioni e interpretazioni diverse
• Se la variabile rappresenta informazioni dal db, incorporare
anche il nome dell’entità
• Sfruttare le informazioni standard disponibili dal database
• Tuttavia, è consigliabile non dichiarare mai variabili con lo
stesso nome di una colonna. E’ possibile, ma cosa accade
se serve adoperare entrambe nella medesima code area?
42. PL/SQL - Alcune convenzioni nel Naming
Cursori
Costanti
Variabili
Parametri
Record e
Record Types
suffisso: company_cur
prefisso: c_earliest_date
prefisso: v_company_id
appendere il parameter mode:
company_id_in
suffisso: company_rec
tot_sales_rectype
43. PL/SQL - Literals
Un literal è un valore esplicito
• Stringhe sono racchiuse tra apici singoli: ‘stringa’
• I booleani sono TRUE, FALSE, NULL senza apici
Permetter l’uso delle costanti esplicite nei programmi
Regole per l’uso degli apici singoli:
• Per comprendere un apice nella stringa, usare due apici
singoli consecutivi
• Per concatenare un apice alla fine di una stringa, usare
tre apici singoli
‘Steven’’s House’ Steven’s House
Literal Value Evaluates To:
‘Steven’ || ‘‘‘s House’ Steven’s House
‘Steven’ || ‘‘‘,’’’ Steven’,’
44. PL/SQL - Commenti
Commenti in singola linea partono con un
doppio tratto (--) e terminano alla fine della
linea fisica
Commenti multi linea partono con (/*) e
fniscono con (*/)
IF status_cd = ‘C’ -- Closed
THEN
/*
|| Reject changes. I have lots to
|| say here so I use a multiple
|| comment block.
*/
action_status := rejected;
END IF;
PROCEDURE calc_totals
/* Return total sales for year. */
(year_in IN INTEGER, arg1 OUT NUMBER);
45. PL/SQL - Symboli e Operatori
PL/SQL supporta l’intero set di operatori
relazionali, più:
Descrizione Simbolo
Assegnamento :=
Concatenazione ||
Identificatore di label << name >>
Diverso != oppure <>
new_total := 1000;
full_name := first_name || last_name;
<<outer_loop>>
IF curr_year != last_year THEN ...
46. PL/SQL - Famiglie di Tipi di Dati
Tipi di Dati PL/SQL per Famiglia
Composti
Scalari
Records
PL/SQL
Tables
BINARY_INTEGER
DEC
DECIMAL
DOUBLE PRECISION
FLOAT
INT
INTEGER
NATURAL
NUMBER
NUMERIC
POSITIVE
REAL
SMALLINT
CHAR
CHARACTER
LONG
LONG RAW
ROWID
STRING
VARCHAR
VARCHAR2
DATE
BOOLEAN
PL/SQL supporta tutti i tipi di dati originari di Oracle
Server, con alcune aggiunte particolari:
47. PL/SQL - Numeri
BINARY_INTEGER sono memorizzati come
numeri binari con segno
• Possono essere usati nei calcoli senza
conversioni, più efficiente
Specificare precisione e scala decimale.
• Scala può essere negativa, che causa
arrotondamenti a sinistra del punto decimale
• Il default è 0 (integers).
• NUMBER supportano un massimo di precisione di
38.
Usare sottotipi per migliorare in qualità e
documentazione del codice
company_count BINARY_INTEGER;
total_sales NUMBER (20,2);
48. PL/SQL - Stringhe
CHAR è a lunghezza fissa e dovrebbe essere
inutilizzato se non per uso specifico (per flag,
risposte quotate, ecc)
VARCHAR2 è a lunghezza variabile e può
arrivare sino a 32Kbytes in lunghezza
• LONG in PL/SQL è più corto di VARCHAR2:
32760.
• Non esiste alcuna ragione specifica per usare
LONG e LONG RAW in PL/SQL
ROWID è un tipo specifico di Oracle che
identifica la LOCAZIONE FISICA di un record.
Il suo formato è: BBBBBBB.RRRR.FFFF
dove BBBBBBB è il numero del blocco del datafile, RRRR è
il numero della riga all’interno del blocco, e FFFF è il valore
HEX del datafile
49. PL/SQL - Date
In PL/SQL i tipi data sono paralleli a quelli previsti nel
RDBMS Oracle
Si compongono di (timestamp):
• Secolo, Anno, Mese, Giorno
• Ore, Minuti, Secondi
Non si possono memorizzare frazioni di secondo in una
variabile di tipo data
Le date hanno un intervallo di validità che va dal
1/1/4712 AC al 31/12/4712 DC
Di default, la porzione di tempo è mezzanotte
PL/SQL ha funzioni che permettono operazioni e
manipolazioni sulle date
50. PL/SQL - Booleani
Una variabile dichiarata come BOOLEAN può
essere TRUE, FALSE o NULL
• Questi valori NON sono stringhe
NB: Oracle NON supporta colonne BOOLEAN
• Tipo di dati naturale nella programmazione
• Miglior lettura del codice
• Occorre convertirli in Y/N o 1/0 se si desidera
memorizzare dati Booleani nel database
need_deposit := TRUE;
IF balance_too_low
THEN
...
END IF;
51. PL/SQL - Dichiarazioni
SEMPRE dichiarare tutte le variabili e le
costanti prima di adoperarle
Dichiarare una variabile per stmt
Possibilità di definirne un valore di default in
dichiarzione
Possibilità di applicarne la clausola NOT NULL
• Ma definirne un valore di default
Usare gli attributi %TYPE e %ROWTYPE per
ancorare la variabile ad una variabile
esistente o ad un elemento di db
DECLARE
<var_name> <datatype>
[ NOT NULL ]
[ := <def_value> ];
52. PL/SQL - Esempi di Dichiarazioni
Senza vincoli:
hire_date DATE;
total_sales NUMBER;
balance_too_low BOOLEAN;
Vincolate e con defaults
ename VARCHAR2(30) DEFAULT ‘ACME’;
sales_amt NUMBER(15,2) NOT NULL := 0;
Costanti
closed_status CONSTANT CHAR(1) := ‘C’;
Dichiarazione Ancorata
ename emp.ename%TYPE;
total_sales sales_amt%TYPE;
emp_rec emp%ROWTYPE;
53. PL/SQL - Ancoraggio
DECLARE
ename emp.ename%TYPE;
new_emp_name ename%TYPE;
BEGIN
ename
empno
hiredate
VARCHAR2(60)
NUMBER
DATE
The emp table structure
54. PL/SQL - Ancoraggio i Vantaggi
Il meccanismo dell’ancoraggio sincronizza le
variabili PL/SQL con righe e colonne di
database
• Se una variabile o un parametro PL/SQL dovrà
rappresentare una informazione di database nel
programma userà SEMPRE %TYPE or
%ROWTYPE.
• Mantengono il programma in sintonia con le
strutture del db senza grosse modifiche del
codice
L’ancoraggio normalizza le dichiarazioni delle
variabili derivate
• Essere certi della consistenza dei nomi di entità
• Ricompilare gli upgrade e le modifiche fatte ad
una dichiarazione
55. PL/SQL - il NULL in PL/SQL
NULL significa “indeterminato”
• Non equivale a 0 o blank
• NULL non è mai uguale a nient’altro, nemmeno
a NULL
• NULL non è mai diverso da nient’altro
Quando si applica un NULL come argomento
di una funzione, in ritorno si ha NULL.
Eccezioni:
• NVL: converte NULL in un altro valore
• La concatenazione ignora i NULL
• REPLACE: NULL causa la rimozione di caratteri
da stringhe
Usare IS NULL e IS NOT NULL per accertarsi
della presenza di null values
56. PL/SQL - Null nelle Funzioni
Normalmente, un argomento NULL gemera il
return di valori NULL
TO_DATE (NULL) NULL
NVL converts a NULL:
NVL (NULL, ‘N/A’) ‘N/A’
Concatenation ignores null values:
‘Steven ‘ || NULL || ‘Feuerstein’ ‘Steven Feuerstein’
Certamente è rara la codifica pura di NULL negli statements. NULL è
invece un valore assunto da una variabile
57. PL/SQL - Null da Verificare
ATTENZIONE ! Le seguenti condizioni NON
verranno mai valutate con TRUE
Remember: niente è mai uguale o diverso da
NULL
emp_rec.hiredate IS NULL
emp_rec.hiredate IS NOT NULL
Adoperare gli operatori IS NULL e IS NOT NULL:
emp_rec.hiredate = NULL
emp_rec.hiredate != NULL
NULL = NULL
58. PL/SQL - Scope e Visibilità
Una volta dichiarata una variabile o, più in generale, un
identificatore è lecito adoperarli
Si faranno riferimenti ad esso nel codice
PL/SQL risolve i riferimenti alle variabili con regole baste
su scope e visibilità.
SCOPE è la porzione di codice all’interno della quale è
possibile fare riferimento ad un identificatore
Un identificatore è VISIBILE se è possibile fare ad esso
riferimento con un nome non qualificato
I nomi qualificati sono quelli per cui vale la “dot
notation”, come per tabella.colonna o package.modulo
or record.campo
59. PL/SQL - Scope and Visibilità nei
blocchi annidati
DECLARE
N NUMBER;
BEGIN
...
DECLARE
N NUMBER;
BEGIN
...
END;
...
END;
DECLARE
N NUMBER;
BEGIN
...
DECLARE
N NUMBER;
BEGIN
...
END;
...
END;
DECLARE
N NUMBER;
BEGIN
...
DECLARE
N NUMBER;
BEGIN
...
END;
...
END;
DECLARE
N NUMBER;
BEGIN
...
DECLARE
N NUMBER;
BEGIN
...
END;
...
END;
Scope Visibilità
Outer
N
Inner
N
60. PL/SQL - Referenziamento
PL/SQL richiede un riferimento “qualificato”
per distinguere due oggetti con lo stesso nome
ma dichiarati in scope diversi
<<outer_block>>
DECLARE
total_sales NUMBER;
BEGIN
<<inner_block>>
DECLARE
total_sales NUMBER;
BEGIN
total_sales :=
outer_block.total_sales;
END;
display_totals (total_sales);
END;
61. PL/SQL - Precedenze tra SQL e
PL/SQL
Si possono eseguire stmt SQL da dentro
PL/SQL
Regole generali per la precedenza:
SQL ha SEMPRE precedenza su PL/SQL
• Dentro uno statement SQL, PL/SQL cerca prima
di risolvere tutti i referimenti ad oggetti del
database
• Anche nel PL/SQL nativo, si cerca spesso di
interpretare gli identificatori che hanno un
match con gli oggetti del db come oggetti di
database
La soluzione migliore è di concedere il
naming di oggetti PL/SQL come gli oggetti
del db
v_company_id company.company_id%TYPE;
62. Consigli Finali - Evitare
sovrapposizioni nel Naming
Nonostante PL/SQL fornisca strumenti molto
flessibili per la definizione di “qualcosa”, è
consigliabile NON adoperare nomi che si
sovrappongono o che creano conflitti per le
decisioni del compilatore
• Adoperare block labels, loop labels, nomi di
moduli e di package, ecc.
• Perché affaticare il lavoro del compilatore ?
Se possibile, evitare l’uso di nomi uguali o
cnflittuali per identificatori
• Invece di adoperare label e “sperare” in un non
conflitto, usare nomi univoci
• E usarli in maniera consistente
63. Consigli Finali - Stile di
Programmazione (1)
I programmi sono più leggibili e gestibili se si
sviluppo in maniera consistente ed elegante
• Stabilire standard di sviluppo per lo stesso team
• Al minimo, pensare che ogni sviluppatore sia
“internamente consistente”
Il seguente esempio confronta due stili di
programmazione:
Quale dei due è più semplice da capire, e di
conseguenza, più semplice da gestire?
64. Consigli Finali - Function #1
function
calc_total (year_in IN
NUMBER, cid NUMBER) return number IS BEGIN /* If in
current century,
then calculate company sales.*/
if year_in = to_number(to_char
(sysdate,’YYYY’)) then return comp_sales(cid);
/* If previous century no sales. */
elsif year_in < 1900
then
return 0;
end if; end;
Tutto qui ? … Che roba è ?
Anche se con i commenti è difficile seguire il filo
logico del programma
65. Consigli Finali - Function #2
FUNCTION total_sales
(year_in IN INTEGER,
company_id
company.company_id%TYPE)
RETURN NUMBER
IS
curr_year CONSTANT INTEGER :=
TO_CHAR (SYSDATE, ‘YYYY’);
BEGIN
IF year_in = TO_NUMBER (curr_year)
THEN
RETURN comp_sales (company_id);
ELSIF year_in < 1900
THEN
RETURN 0;
END IF;
END total_sales;
Qui non vi è bisogno di commento per capire
come va il programma !!!
66. Consigli Finali - Stile di
Programmazione (2)
Delegare quanto possibile ad una buona codifica
dei costrutti del linguaggio PL/SQL la pseudo
documentazione del codice
Rafforzare l’uso di strutture locali nel programma
Usare maiuscolo/minuscolo per diversificare il
codice tra le parole chiave e le variabili o
identificatori
Parole Chiave Identificatori specifici di Appl.
TO_CHAR company_id
PROCEDURE total_sales_in
ELSIF balance_too_low
67. Consigli Finali - Indentare gli stmt
SQL
Gli statements SQL sono complessi e non
procedurali
• Un formato consistente è fondamentale per la
loro comprensione
Consigli:
• Separare ed Allineare le diverse clausole degli
stmt
SELECT empno, ename
FROM emp, dept
WHERE emp.deptno = dept.deptno
AND dept.deptno = 100
ORDER BY ename
UPDATE emp
SET sal = sal * 2
WHERE deptno = 100
68. Consigli Finali - Esempio di Hard-to-
Read SQL Stmt
Nessuno di noi ha mai scritto nulla di simile, vero
?
Usare ABC... per gli alias di tabella è interessante:
rappresenta un metodo semplice e consistente
senza alcun significato
select company_id, SUM (sales),
address1, company_type_ds description, min_balance
FROM
company A, sales_amount B, company_type C, company_config D,
region E, regional_status F WHERE
A.company_id = B.company_id and
A.company_type_cd = C.company_type_cd
and C.company_type_cd = D.company_type_cd and A.region_cd =
E.region_cd and E.status = F.status;
69. Consigli Finali - Chiara lettura dello
stmt SQL
Netta separazione tra le clausole
Relazioni e significato della query sono molto
più evidenti
SELECT company_id, SUM (sales),
address1,
company_type_ds description,
min_balance
FROM company COM,
sales_amount SAL,
company_type TYP,
company_config CFG,
region REG,
regional_status RST
WHERE COM.company_id = SAL.company_id
AND COM.company_type_cd =
TYP.company_type_cd
AND TYP.company_type_cd = CFG.company_type_cd
AND COM.region_cd = REG.region_cd
AND REG.status = RST.status;
70. Consigli Finali - Indentare in
PL/SQL
Usare 2 - 4 spazi per indentare (o TAB).
Indentare per ogni cambiamento della logica dello
scope: IF, LOOP, exceptions, ecc
Andare a capo per enfatizzare la logica di
programma
FUNCTION column_name
(type_in IN VARCHAR2 := 'FULL')
IS
colname VARCHAR2(100) :=
NAME_IN ('GLOBAL.col_'||list_name);
BEGIN
IF type_in = 'FULL'
THEN
RETURN colname;
ELSE
RETURN SUBSTR (colname, 10, 6);
END IF;
END;
71. Consigli Finali - Indentare un
Esempio
IF condition
THEN
executables;
ELSIF condition
THEN
executables;
END IF;
WHILE loop_condition
LOOP
executables;
END LOOP;
LOOP
executables;
END LOOP;
PROCEDURE ...
IS
declarations;
BEGIN
executables;
EXCEPTION
WHEN exception
THEN
executables;
END;
PACKAGE package
IS
FUNCTION ...
PROCEDURE ...
END package;
72. Consigli Finali - Blank
Usare righe vuote per:
• Separare distintamente sezioni di codice da sezioni di
dichiarazione, sezioni di exception handling, ecc.
• Per separare i cambiamenti nei livelli logici di
programma, tra IF e loop e blocchi annidati
DECLARE
/* Starting location of search */
start_loc INTEGER := 0;
/* Last character analyzed */
curr_char VARCHAR2(1);
BEGIN
DECLARE
END;
IF <condition>
THEN
END IF;
END;
73. Consigli Finali - I Commenti
Non adoperarli per ripetere quello già espresso
chiaramente dal codice
Usarli per tradurre un computer-lang in una
regola di business
Indentare i commenti allo stesso livello del codice
che commentano
Commentare ogni stmt di dichiarazione
Commentare mentre si codifica, cercare di non
farlo a posteriori
74. Consigli Finali - Esempi di
Commento
Alta gestione:
Bassa gestione:
/*--------------------------------*
* Molto carino da vedersi *
* ma molto operoso da gestire *
* quando vi sono modifiche! *
*--------------------------------*/
/*
|| Questo formato è più grezzo
|| ma più semplice da modificare
|| quando vi sono cambiamenti
|| senza occuparsi dei bordi.
*/
Soluzione migliore: brevi commenti su linee di codice. Sigh....
75. Adottare uno Stile Personale OK?!?
Nessun problema… se non si preferisce seguire la
letteratura
L’importante è definirsi un proprio stile ed
applicarlo sistematicamente e rigorosamente con
l’obiettivo di migliorare la documentazione e la
manutenzione successiva del codice
Le mie regole o nessun’altra ?