SQL nei linguaggi di programmazione Atzeni, Ceri, Paraboschi, Torlone Basi Di Dati Modelli e Linguaggi di Interrogazione, McGraw-Hill Italia, Capitolo 6 SQL in Linguaggi di Programmazione L uso diretto dell interprete SQL è tipicamente riservato a pochi utenti esperti. L utente generico accede alla base di dati attraverso applicazioni scritte usando linguaggi tradizionali di alto livello o speciali. I linguaggi tradizionali sono di tipo procedurale mentre SQL è un linguaggio dichiarativo. Le istruzioni SQL sono allora incapsulate nel linguaggio e passate all interprete tramite opportune chiamate. Bisognerà allora dotare il compilatore di un pre-processore per la rilevazione di tali chiamate. SQL 1 SQL in Linguaggi di Programmazione Stored Procedures SQL Uso diretto Linguaggi ad hoc In linguaggi classici Stored Prcedures Triggers SQL Embedded Call Level Interface ODBC JDBC Statica Dinamica Soluzioni Proprietarie Procedure che vengono memorizzate come parte dello schema Lo standard SQL-2 si occupa solo di procedure costituite da un solo comando SQL Procedure AssegnCitta ( :Dip varchar(20), :Citta varchar(20)) update Dipartimento set Citta = :Citta where Nome=:Dip exec AssegnaCitta( Amministrazione, Milano ).. SQL 2 SQL 3
Stored Procedures I sistemi commerciali estendono la sintassi prevedendo sequenze di comandi e/o (alcune) strutture di controllo mettendo di fatto a disposizione dei veri e propri linguaggi di programmazione Anche SQL-3 estende notevolmente la sintassi a disposizione Stored Procedures: PL/SQL Procedure Addebita ( codcont char(5), Prelievo integer) is AmmontarePrec integer; NuovoAmmontare integer; Limite integer; begin select ammontare, scoperto into AmmontarePrec, Limite from CC where Codice = codconto for update of Ammontare NuovoAmmontare = AmmontarePrec Prelievo if NuovoAmmontare > Scoperto then update CC set Ammontare = nuovoammontare Prelievo where Codice= codconto; else insert into T values(codconto,prelievo,sysdate); endif end Addebita SQL 4 SQL 5 Stored Procedures: SQLSERVER CREATE PROC count_tables @authorcount int OUTPUT, @titlecount int OUTPUT AS SELECT * FROM authors SET @authorcount=@@rowcount SELECT * FROM titles SET @titlecount=@@rowcount RETURN(0) DECLARE @a_count int, @t_count int EXEC count_tables @a_count OUTPUT, @t_count OUTPUT Triggers I triggers sono (in estrema sintesi) delle stored procedures che scattano in relazione ad eventi. Evento Condizione Azione (ECA) Se c è un evento (insert, update e delete su una certa tabella) ed è verificata una certa condizione (un predicato SQL) viene eseguita una certa azione (un singolo comando SQL od una intera procedura) Definiti a livello di standard da SQL-3, ma presenti nei sistemi (con sintassi e caratteristiche diverse) già dalla fine degli anni Ottanta. SQL 6 SQL 7
Triggers Si possono creare delle catene di esecuzione difficili da analizzare In Oracle before, after row, statement Esempio di Trigger Oracle create trigger Ordine after update of QtaDisp on Magazzino when (new.qtadisp < new.qtasoglia) for each row declare X number; begin select count(*) into X from OrdiniPendenti where Parte = new.parte; if X =0 then insert into OrdiniPendenti values(new.parte,newqtariord, sysdate) end SQL 8 SQL 9 SQL nei linguaggi tradizionali: Il Problema del Conflitto di Impedenza Un linguaggio tradizionale scandisce gli elementi di una tabella riga per riga (approccio tuple oriented). SQL lavora su tabelle, essendo il risultato di una query una tabella (approccio set-oriented). Soluzioni: Utilizzo di Cursori. Utilizzo di linguaggi con costruttori di tipi complessi (OO). Cursori Un cursore consente ad un programma di ispezionare le riga di una tabella una per una. Viene dichiarato con riferimento ad una interrogazione declare NomeCur [scroll] cursor for SelectSql [for <read only update [Attributo {, Attributo}]>] open NomeCur fetch [Posizione from] NomeCur into ListaDiFetch SQL 10 SQL 11
Cursori (continua) Posizone: next, prior, first, last, absolute ExprInt, relative ExprInt Se l opzione scroll non è specificata, l unica scelta possibile è next. L opzione scroll spesso comporta che venga costruita una materializzazione completa del risultato. Se non è specificata il sistema ha più gradi di libertà e può, ad esempio, costruire il risultato una riga alla volta e passare man mano le righe al chiamante velocizzando le elaborazioni su query che restituiscono molte righe. Cursori (continua) declare CurImp for Impiegati select * from Impiegati where stip > 40. open CurImp update nometab set Attributo= <Espr null default> {, set Attributo= <Espr null default>} where current of NomeCur delete from NomeTab where current of NomeCur close NomeCur SQL 12 SQL 13 Cursori SQLSERVER DECLARE cursor_name CURSOR [LOCAL GLOBAL] [FORWARD_ONLY SCROLL] [STATIC KEYSET DYNAMIC FAST_FORWARD] [READ_ONLY SCROLL_LOCKS OPTIMISTIC] [TYPE_WARNING] FOR select_statement [FOR UPDATE [OF column_list]] Cursori SQLSERVER (cont.) Local / Global I cursori sono globali (default) per l intera connessione. Con Local indichiamo che il cursore è locale, ad esempio, alla stored procedure in cui è definito [FORWARD_ONLY SCROLL] Ha il significato descritto precedentemente. SQL 14 SQL 15
Cursori SQLSERVER (cont.) STATIC Sono cursori statici che cioè non riflettono modifiche sui dati (nel caso in esame si crea una copia in tempdb). Nei cursori ANSI la parola chiave è Insensitive. Il default per Static diventa Scroll (diverso dall ANSI). KEYSET Con un cursore Keyset viene mantenuta una lista dei valori di chiave che soddisfano ai criteri della query. In questo modo i cambiamenti effettuati da altri utenti sono visibili. Non sono visibili inserimenti di nuove righe che soddisfano la query. Cursori SQLSERVER (cont.) DYNAMIC In questo caso abbiamo che la Select è virtualmente riapplicata ad ogni FETCH. FAST_FORWARD Read_only + forward_only SQL 16 SQL 17 SQL embedded #include <stdio.h> main() { exec sql begin declare section; char *nomedip = manutenzione ; char *cittadip = Roma ; exec sql end declare section; exec sql connect to pippo@librodb; if (sqlca.sqlcode!= 0) { printf( errore\n ); return; } exec sql insert into dipartimento values (:nomedip, :cittadip); if (sqlca.sqlcode!= 0) { printf( errore\n ); return; } exec sql disconnect all; } SQL Dinamico Con la soluzione embedded l interrogazione deve essere nota a tempo si compilazione. Quando la struttura delle interrogazioni è molto variabile, l approccio appena descritto (SQL statico) non è più utilizzabile in modo efficiente. Si può allora consentire all utente di accedere all interprete SQL, con costi notevoli in termini di training e con problemi legati all integrazione con le applicazioni. Una possibilità alternativa è costituita dal SQL dinamico che permette di costruire programmi che effettuano interrogazioni costruite a run-time. SQL 18 SQL 19
SQL Dinamico (continua) comandosql = delete.. execute immediate :comandosql è utilizzabile solo se non si hanno parametri di ingresso e\o di uscita. Il vantaggio dell SQL statico: i comandi SQL sono passati ad un compilatore che li traduce nel linguaggio interno del sistema. Ogni qual volta il programma è eseguito, il comando SQL non deve essere tradotto dall interprete SQL. E in qualche modo possibile mantenere tale vantaggio nel SQL dinamico. Tale seconda forma è inoltre l unica possibile nel caso in cui esistono parametri di ingresso e\o di uscita. SQL Dinamico (continua) prepare NomCom from ComSql Analizza il comando e lo traduce nel linguaggio procedurale interno del sistema. prepare :comando from select Citta from Dipartimento where nome=? execute :comando into :citta using :dipartimento declare cursor from NomeCom deallocate prepare NomeCom SQL 20 SQL 21 Call Level Interface Mettono a disposizione del programmatore una serie di funzioni che interagiscono con il DBMS. ODBC OLE DB, ActiveX Data Object (ADO), ADO.NET JDBC Soluzioni proprietarie CLI: Passi fondamentali Ci si connette al DMBS Si invia al DBMS una stringa che rappresenta il comando SQL Si riceve il risultato in un opportuno formato Si analizza attraverso alcune primitive il risultato Si chiude la connessione SQL 22 SQL 23
CLI: Struttura Applicazione Connessione Connessione Connessione ODBC Open Data Base Connectivity, proposta dalla Microsoft Soluzione molto ricca e potente Comandi SQL Comandi SQL Comandi SQL SQL 24 SQL 25 JDBC Tipo 1 Il driver è scritto in formato nativo e le richieste JDBC vengono convertite Tipo 2 JDBC/ODBC bridge Middleware server Drive JAVA Package java.sql.* Connection Statement PreparedStatement ResultSet SQL 26 SQL 27
JDBC: Esempio import java.sql.*; public class PrimoJDBC { public static void main (String [] arg) { Connection conn = null; try{ Class. froname (sun.jdbc.odbc.jdbcodbcdriver); conn = DriverManager.getConnection( jdbc:odbc:swbd,u,p); } catch (ClassNotFoudException e) {..} catch (SQLException e) {} JDBC: Esempio try { Statement stm = conn.createstatement(); String query = select * from impiegato ; ResultSet rst = stm.executequery(query); while (rst.next()) { String matricola = rst.getstring( matr ); int stipendio = rst.getint( stipendio ); } catch (SQLEcception e ) { } }} SQL 28 SQL 29 CreateStatement Connection.createStatement() Connection.createStatement(int type, int concurrency) Type: TYPE_FORWARD_ONLY TYPE_SCROLL_INSENSITIVE, TYPE_SCROLL_SENSITIVE Concurrency CONCUR_READ_ONLY CONCUR_UPDATABLE java.sql.statement ResultSet executquery(string query) ritorna il risultato della query in un ResultSet int executeupdate usato principalmente per insert, update, delete ritorna il numero di righe modificate/candellate/inserite o 0 de il comendo non torna nulla SQL 30 SQL 31
PreparedStatement Connection.prepareStatement(Strng query) Connection.prepareStatement(String quey,int type, int concurrency) Esempio PreparedStatement pstmt = con.preparestatement ("UPDATE EMPLOYEES SET SALARY =? WHERE ID =?"); pstmt.setdecimal(1, 153833.00) pstmt.setint(2, 110592) pstmt.execute(); SQL 32