Basi di Dati e Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
Giuseppe Loseto
Corso di Laurea in Ing. Informatica – Ing. Gestionale Magistrale
Uso di SQL nei linguaggi
di programmazione
 Interazione con basi di dati utilizzando SQL non è diretta, ma attraverso
l’uso di programmi applicativi
 Linguaggi di quarta generazione (4GL) come Informix4GL che
permettono di sviluppare complete applicazioni per la gestione di basi di
dati
 SQL da solo non è Touring-Completo
 Impedence mismatch (“disaccoppiamento di impedenza”) fra base di
dati e linguaggio di programmazione
 I linguaggi operano tipicamente su singole variabili o oggetti mentre SQL
opera su relazioni (insiemi di tuple)
 In alcuni approcci la soluzione ai problemi di interazione è rappresentata
dall’uso dei cursori
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
2 di 31
Approcci Principali
 SQL embedded (SQL “integrato”)
 SQL Statico
 SQL Dinamico
 Call Level Interface (CLI)
 Stored Procedures
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
3 di 31
SQL Embedded






Tecnica sviluppata sin dagli anni ‘70
SQL è “ospitato” in un linguaggio di programmazione, chiamato
linguaggio ospite (Java, Pascal, Cobol, C, C++, …), in quanto questi
standard hanno definito l’interfaccia con SQL
Il codice sorgente contiene sia codice nel linguaggio di programmazione
che codice SQL
Un preprocessore, dipendente sia dal linguaggio ospite che dalla
piattaforma del DBMS, viene usato per analizzare il codice
Le istruzioni SQL sono tradotte con chiamate alle funzioni di una API del
DBMS prima della compilazione vera e propria
Ogni programma che usa Embedded SQL deve:
1. Definire quale database usare
2. Connettersi al database
3. Effettuare le operazioni sul database (usando cursori e statement SQL)
4. Disconnettersi dal database
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
4 di 31
Esempio in C di SQL statico (1/2)
#include<stdlib.h>
#include<stdio.h>
#include<sqlenv.h>
main()
{
exec sql begin declare section; /*dichiarazione variabili*/
char *NomeDip = “DEE";
int Id_Dip = 3;
exec sql end declare section; /*fine della dichiarazione variabili*/
exec sql connect to esempio@azienda_esempio;
if (sqlca.sqlcode != 0) {
/*sqlca (SQL Communication Area) è una struttura di dati predefinita che mantiene le informazioni sulla comunicazione tra SQL e
programma, sqlcode=0 no errore, altrimenti codice dell’errore*/
printf(“Errore di connessione al DB\n"); }
else {
exec sql insert into Dipartimento
values(:NomeDip,:Id_Dip);
/* notare l’uso del : per utilizzare le variabili del programma ospite in SQL*/
exec sql disconnect all;
}
}
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
5 di 31
Esempio in C di SQL statico (2/2)
main()
{
exec sql connect to universita
user pguser identified by pguser;
exec sql create table studente (matricola integer primary key,
nome varchar(20),
annodicorso integer);
exec sql disconnect;
}
/* These include files are added by the preprocessor */
#include <ecpgtype.h>
#include <ecpglib.h>
#include <ecpgerrno.h>
#include <sqlca.h>
main()
{
ECPGconnect(__LINE__, "universita" , "pguser" , "pguser" , NULL, 0);
ECPGdo(__LINE__, NULL, "create table studente ( matricola integer primary key , nome varchar ( 20 ) , annodicorso
integer )", ECPGt_EOIT, ECPGt_EORT);
ECPGdisconnect(__LINE__, "CURRENT");
}
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
6 di 31
Cursori
 Quando una query restituisce più tuple è necessario passarle al
programma ospite una per volta
 Si utilizza un cursore per accedere a tutte le tuple di una interrogazione
in modo globale (tutte insieme o a blocchi – è il DBMS che sceglie la
strategia efficiente)
 Il cursore passa poi una tupla per volta al programma
 Un cursore viene definito su una generica interrogazione mediante la
seguente sintassi
declare Cursor_Name [scroll ] cursor for
SelectSQL [for <read only| update [of attribute,{attribute}]>]
Dove, scroll indica che il cursore può muoversi liberamente sul risultato
della query, mentre for update indica che il cursore può essere utilizzato in
operazioni di aggiornamento permettendo di specificare eventualmente
gli attributi oggetto del comando.
Si osservi che per riga corrente si considera l’ultima riga letta.
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
7 di 31
Utilizzo di un cursore (1/2)
 Apertura cursore ed esecuzione della query:
open Cursor_Name
 Utilizzo dei risultati (una ennupla alla volta):
fetch [position from] Cursor_Name into Variables
accede alla tupla corrente o a quella indicata da position e copia i valori
nelle variabili del programma ospite
 Position (utilizzabili se l’opzione scroll è stata impostata, altrimenti è
disponibile solo next):
 next (con riferimento a current indica la prossima tupla);
 prior (tupla precedente);
 first (prima tupla);
 last (ultima tupla);
 absolute integer_value (tupla posizionata al valore ordinale espresso)
 relative integer_value (tupla posizionata al valore ordinale espresso, rispetto alla
posizione corrente)
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
8 di 31
Utilizzo di un cursore (2/2)
 Accedere alla tupla corrente di un cursore per effettuare un update o un
delete
Delete from NomeTabella where current of Cursor_Name
 Chiusura del cursore
close cursor Cursor_Name
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
9 di 31
Esempio di cursore in C
……
printf(“nome della citta‘?”);
scanf(“%s”,&citta[0]);
/*creo il cursore*/
EXEC SQL DECLARE P CURSOR FOR SELECT NOME, REDDITO
FROM Impiegato
WHERE CITTA = :citta for UPDATE of REDDITO;
EXEC SQL OPEN P ; /* apro il cursore -> eseguo la query*/
EXEC SQL FETCH P INTO :nome, :reddito ; /*prelevo i dati*/
while (sqlca.sqlcode == 0)
{
printf(“Qual è l’aumento per %s? ”, nome);
scanf(“%d”,&aumento);
EXEC SQL UPDATE Impiegato SET REDDITO = REDDITO + :aumento
WHERE CURRENT OF P; /*eseguo l’update su current*/
EXEC SQL FETCH P INTO :nome, :reddito; ; /*prelevo i dati per la tupla immediatamente successiva*/
}
EXEC SQL CLOSE CURSOR P;
} …..
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
10 di 31
SQL Dinamico
 Non sempre le istruzioni SQL sono note quando si scrive il
codice ospite
 SQL statico
 i nomi delle relazioni e degli attributi coinvolte nelle istruzioni SQL sono fissate
a priori
 l’unica parte delle istruzioni che può rimanere non nota a tempo di
compilazione è costituita dagli specifici valori da ricercare o da aggiornare
 SQL dinamico
 le istruzioni SQL sono generate a tempo di esecuzione
 non è quindi necessario specificare relazioni e attributi coinvolti in una
istruzione SQL prima della sua esecuzione
 degrado delle prestazioni
 operazioni eseguite immediatamente oppure preparate e poi eseguite (anche
più volte)
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
11 di 31
Modalità di esecuzione
Le operazioni SQL possono essere

Con esecuzione immediata (in assenza di parametri)
execute immediate SQLStatement
Esempio:
Char *SQL_string=“delete from Impiegato where CF=27”;
exec sql execute immediate :SQL_string;
Con esecuzione differita e ripetibile (anche con parametri):
prepare CommandName from SQLStatement
execute CommandName [into TargetList][using ParameterList]
Esempio:
Prepare :trova_nome From “Select nome From Impiegato Where CF =?”
Execute :trova_nome into :nome_imp using :cf_imp
Deallocate prepare :trova_nome
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
12 di 31
Call Level Interface

Application Programming Interface (API) per accedere ai database

Insieme di funzioni chiamabili direttamente dal linguaggio di programmazione
usato

Ogni DBMS mette a disposizione una libreria di funzioni, che seguono lo standard
CLI

Generalmente vengono usate per applicazioni basate su SQL dinamico
API
Oracle
Oracle
Prog
C
API
Interbase
Interbase
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
13 di 31
Evoluzione di CLI

Utilizzare uno strato software che si interpone tra l’applicazione e i driver specifici
del database

Consente ai programmi applicativi di usare query standard SQL, che accederanno
al database, senza necessità di conoscere la particolare interfaccia proprietaria

Interfacciare qualsiasi database tramite un driver specifico (es. ODBC, JDBC)
Driver
Oracle
Prog
JAVA
API
Comune
Driver
Interbase
Basi di Dati e
Sistemi Informativi
Oracle
Sviluppo di applicazioni per Basi di dati
Interbase
14 di 31
Implementazioni delle CLI
ODBC (Open Database Connectivity)
 implementazione proprietaria (Microsoft) di SQL/CLI (altra CLI parte di
SQL:1999)
 accesso a basi di dati relazionali in un contesto eterogeneo e distribuito
 originariamente rilasciata nel 1992, consente di accedere a database di
numerosissimi costruttori, inclusi Microsoft (jet, Access, SQLServer); Oracle,
IBM, Informix e numerosi altri
JDBC (Java Database Connectivity)
 API Java sviluppata da JavaSoft per eseguire istruzioni SQL
 consente ai programmi Java di interagire con qualunque database
 JDBC rende possibile scrivere una singola applicazione di database che può girare
indifferentemente su piattaforme diverse e interagire con diversi database
 simile a ODBC ma è progettato per Java mentre ODBC è indipendente dal
linguaggio di programmazione.
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
15 di 31
Accesso con JDBC
In generale le operazioni richieste sono:
 caricamento del driver
 apertura della connessione con la base di dati
 richiesta di esecuzione di istruzioni SQL
 elaborazione dei risultati delle istruzioni SQL
Le funzioni di accesso al DBMS possono essere realizzate tramite:
 JDBC/ODBC Bridge
 Driver Nativo
 Middleware-server
 Driver Java
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
16 di 31
ODBC e ADO
 ODBC richiede una certa familiarità di programmazione con le API ed è
sostanzialmente procedurale (Scritta in C).
 Successivamente Microsoft ha introdotto altre due API, questa volta orientate agli
oggetti
 DAO (Data Access Object)
 RDO (Remote Data Object)
 Definiscono interfacce ActiveX (originariamente COM Component Object Model)
 ADO (Active Data Object), basata su una nuova tecnologia di programmazione delle
interfacce per DB nota come OLE DB (Object Linking and Embedding for
DataBases)
 In ODBC ogni tipo di DB deve avere una DLL (Dynamic Link Library) e un driver
ODBC, che viene utilizzata dal motore ODBC per accedere allo specifico DB.
 In OLE DB is hanno ancora dei driver, ma questi sono implementazioni ActiveX, cioè
definizioni di classi che implementano delle interfacce, eliminando così i livelli
interposti tra il programma e lo specifico DBMS che si sta utilizzando
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
17 di 31
Basi di ADO
ADO è composto essenzialmente da tre oggetti primari
 Connection Object: responsabile di raccogliere tutte le informazioni necessarie
alla creazione del RecordSet
 RecordSet: fornisce la struttura atta a contenere i dati e i metodi necessari per
accedere ai dati. Tutte le funzionalità dei cursori sono rappresentati nell’interfaccia
del RecordSet
 Command Object: fornisce un secondo metodo per creare un RecordSet, ed è
stato esplicitamente progettato per passare i parametri alle stored procedure
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
18 di 31
SQL Embedded vs CLI
SQL embedded
 pemette precompilazione (e quindi efficienza e portabilità del sorgente)
 uso di SQL completo
 Molto usato in applicazioni legacy
CLI
 indipendente dal DBMS, uso di funzioni di interazione con i DBMS
attraverso Application Programming Interfaces (API)
 permette di accedere a più basi di dati, anche eterogenee (senza
ricompilazione: portabilità dell’eseguibile)
 richiede un ulteriore strato di comunicazione
 esistono drivers specifici per i vari DBMS
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
19 di 31
Stored Procedure
 A partire da SQL-2 è possibile definire procedure dette stored procedures per il fatto che
vengono memorizzate all’interno della base di dati come parti dello schema
 Le procedure permettono di associare un nome ad una o più istruzioni SQL, con la possibilità
di specificare dei parametri da utilizzare per lo scambio di informazioni con la procedura
 Caratteristiche:
 minor quantità di dati trasferita tra client e server
 più facile manutenibiltà
 riutilizzo della logica dell’applicazione da parte di utenti diversi
 sensibile incremento delle prestazioni
 logica di business in gran parte inglobata nella base di dati
 Una volta che la procedura è definita, essa è utilizzabile come se facesse parte dell’insieme
dei comandi SQL predefiniti
 La procedura può essere invocata avendo cura di associare un valore ai parametri.
procedure Update_address(:cod_dip int, :Addr varchar(60))
Begin;
update Department set Address =:Addr where ID_dip =:cod_dip
End;
exec sql Update_address(:codice,:indirizzo);
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
20 di 31
PL/SQL (Procedural Language/SQL)
Oracle PL/SQL: estensione più ricca e più complessa (ad es. costrutti if – else, cicli
while) che rendono SQL un linguaggio computazionalmente completo ossia con lo
stesso potere espressivo di un normale linguaggio di programmazione.
DECLARE
/* Declarative section: variables, types, and local subprograms. */
BEGIN
/* Executable section: procedural and SQL statements go here. */
/* This is the only section of the block that is required. */
EXCEPTION
/* Exception handling section: error handling statements go here.
*/
END;
Per eseguire un programma PL/SQL al testo bisogna far seguire:
Una riga con .
Una riga con run
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
21 di 31
Variabili e Tipi
Una variabile unbound ha sempre valore NULL. Esistono i tipi di SQL, ma anche tipi nuovi, quali Number
DECLARE
price
NUMBER;
myBeer VARCHAR(20);
Usare %TYPE:
DECLARE
myBeer Beers.name%TYPE;
/* Assegna direttamente a myBeer il tipo di name */
Usare %ROWTYPE per definire record strutturati:
DECLARE
beerTuple Beers%ROWTYPE;
Assegnare valori
DECLARE
a NUMBER := 3;
BEGIN
a := a + 1;
END;
.
run;
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
22 di 31
Esempio Base
CREATE TABLE T1(e INTEGER, f INTEGER );
INSERT INTO T1 VALUES(1, 3);
INSERT INTO T1 VALUES(2, 4);
/* Above is plain SQL; below is the PL/SQL program. */
DECLARE
a NUMBER;
b NUMBER;
BEGIN
SELECT e,f INTO a,b FROM T1 WHERE e>1;
INSERT INTO T1 VALUES(b,a);
END;
.
run;
Si noti l’obbligo della keyword INTO
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
23 di 31
Flusso di controllo: IF
IF <condition> THEN <statement_list>
ELSE <statement_list>
END IF; la parte ELSE è opzionale.
Si può fare multiway branch:
IF <condition_1> THEN ... ELSIF <condition_2> THEN ... ... ... ELSIF
<condition_n> THEN ... ELSE ... END IF;
Esempio:
DECLARE
a NUMBER;
b NUMBER;
BEGIN
SELECT e,f INTO a,b FROM T1 WHERE e>1;
IF b=1 THEN
INSERT INTO T1 VALUES(b,a);
ELSE
INSERT INTO T1 VALUES(b+10,a+10);
END IF;
END;
Basi di Dati e
.
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
24 di 31
Flusso di controllo: Cicli
LOOP <loop_body> /* A list of statements. Inclusivi di un EXIT WHEN
<condition>;*/
END LOOP;
Esempio:
DECLARE
i NUMBER := 1;
BEGIN
LOOP
INSERT INTO T1 VALUES(i,i);
i := i+1;
EXIT WHEN i>100;
END LOOP;
END;
Esistono anche:
WHILE <condition> LOOP
<loop_body>
FOR <var> IN <start>..<finish> LOOP
Basi di Dati e
Sistemi Informativi
END LOOP;
<loop_body>
Sviluppo di applicazioni per Basi di dati
END LOOP;
25 di 31
Basic I/O
DECLARE
emp_count
NUMBER;
BEGIN
SELECT count(*)
INTO emp_count
FROM employees
WHERE department_id = &department_id;
END;
Produrrà in esecuzione:
Enter value for department_id: 13
Stampare a video:
DBMS_OUTPUT.PUT_LINE(‘hello world’ || emp_count);
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
26 di 31
Usare i cursori
1) DECLARE
/* Declare output variables to hold the result of the query: */
2)
a T1.e%TYPE;
3)
b T1.f%TYPE;
4)
CURSOR T1Cursor AS
5)
SELECT e, f
6)
FROM T1
7)
WHERE e < f
8)
FOR UPDATE;
/* Cursor declaration: */
9) BEGIN
10)
OPEN T1Cursor;
11)
LOOP
/*Retrieve each row of the result of the above query into PL/SQL variables:*/
12)
FETCH T1Cursor INTO a, b;/* If there are no more rows to fetch, exit the loop*/
13)
EXIT WHEN T1Cursor%NOTFOUND;
14)
DELETE FROM T1 WHERE CURRENT OF T1Cursor;
15)
INSERT INTO T1 VALUES(b, a);
16)
END LOOP;
17)
CLOSE T1Cursor;
/* Delete the current tuple: */
/* Insert the reverse tuple: */
/* Free cursor used by the query. */
18) END;
19) .
20) run;
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
27 di 31
Stored procedures in PL/SQL
CREATE TABLE T2 ( a INTEGER, b CHAR(10));
Dichiarazione di una stored procedure:
CREATE|REPLACE PROCEDURE proc_name(var_name IN|OUT|INOUT Data_type) AS|IS
Esempio:
CREATE PROCEDURE addtuple1(i IN NUMBER) AS
BEGIN
INSERT INTO T2 VALUES(i, 'xxx');
END addtuple1;
.
run;
Esecuzione:
BEGIN addtuple1(99); END;
.
run;
Eliminazione:
DROP PROCEDURE <proc_name>
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
28 di 31
Stored Procedures in PL/SQL
CREATE PROCEDURE addtuple2(x IN T2.a%TYPE, y IN T2.b%TYPE)
AS
BEGIN
INSERT INTO T2(a, b)
VALUES(x, y);
END addtuple2;
.
run;
Esecuzione:
BEGIN
addtuple2(10, 'abc');
END;
.
run;
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
29 di 31
Stored Procedures in PL/SQL
CREATE TABLE T3 ( a INTEGER, b INTEGER);
CREATE PROCEDURE addtuple3(a IN NUMBER, b OUT NUMBER) AS
BEGIN
b := 4;
INSERT INTO T3 VALUES(a, b);
END;
.
run;
Eseguiamo la procedura:
DECLARE v NUMBER;
BEGIN
addtuple3(10, v);
END;
.
run;
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
30 di 31
Funzioni
Le funzioni vengono trattate analogamente alle procedure:
CREATE FUNCTION <func_name>(<param_list>)
RETURN <return_type> AS ...
..
RETURN <expression>
Basi di Dati e
Sistemi Informativi
Sviluppo di applicazioni per Basi di dati
31 di 31