Laboratorio di Basi di Dati SQL avanzato Pierluigi Pierini Technolabs S.p.a. Pierluigi.Pierini@technolabs.it
Interrogazioni nidificate Syntax: SELECT {* <val> [, <val> ]} FROM <tableref> [, <tableref> ] [WHERE <search_condition>] <search_condition> = <val> <operator> {<val> (<select_one>)} <val> [NOT] IN (<val> [, <val> ] (<select_list>) {ALL SOME ANY} (<select_list>).. select_one A SELECT on a single column that returns exactly one value select_list A SELECT on a single column that returns zero or more rows
Interrogazioni nidificate Clausola where su predicati logici in cui le componenti sono confronti tra valori Confronto fra un o più attributi ed il risultato di una sottointerrogazione (query annidata) Di solito prima si esegue la query piu interna, ma ci sono eccezioni (es. 5, 6, 7: passaggio di binding)
Interrogazione 0 nome e reddito del padre di Franco select Nome, Reddito from Persone, Paternita where Nome = Padre and Figlio = 'Franco' select Nome, Reddito from Persone where Nome = (select Padre from Paternita where Figlio = 'Franco')
Interrogazioni nidificate, commenti La forma nidificata è meno dichiarativa, ma talvolta più leggibile (richiede meno variabili) La forma piana e quella nidificata possono essere combinate Le sottointerrogazioni non possono contenere operatori insiemistici ( l unione si fa solo al livello esterno ); la limitazione non è significativa
Interrogazioni nidificate regole di visibilità: non è possibile fare riferimenti a variabili definite in blocchi più interni in un blocco si può fare riferimento a variabili definite in blocchi più esterni
Interrogazione 1 Tutti i dati degli impiegati che lavorano in dipartimenti in Firenze select * from Impiegato where Dipart = any (select Nome from Dipartimento where Citta = Firenze ) = any corrisponde a in
Interrogazione 2 Impiegati che hanno lo stesso nome di impiegati del dip di Produzione select I1.Nome from Impiegato I1, Impiegato I2 where I1.Nome = I2.Nome and I2.Dipart = Produzione select Nome from Impiegato where Nome = any (select Nome from Impiegato where Dipart = Produzione )
Interrogazione 3 Dipartimenti in cui non lavorano persone con cognome Rossi select Nome from Dipartimento where Nome <> all (select Dipart from Impiegato where Cognome = Rossi ) <> all corrisponde a not in
Interrogazione 4 Dipartimento dell impiegato che guadagna lo stip massimo select Dipart from Impiegato where Stipendio = (select max(stipendio) from Impiegato) Un solo valore da confrontare select Dipart from Impiegato where Stipendio >= all (select Stipendio from Impiegato)
Interrogazione 5 (passaggio di binding) Data: Persona(CodFiscale, Nome, Cognome, Citta), trovare persone che hanno omonimi select * from Persona P where exist (select * from Persona P1 where P1.Nome=P.Nome and P1.Cognome=P.Cognome and P1.CodFiscale<>P.CodFiscale) Fare in modo diverso, usando 2 istanze (copie) di Persona (senza passaggio di binding)
Interrogazione 6 (passaggio di binding) Data: Persona(CodFiscale, Nome, Cognome, Citta), trovare persone chenon hanno omonimi select * from Persona P where not exist (select * from Persona P1 where P1.Nome=P.Nome and P1.Cognome=P.Cognome and P1.CodFiscale<>P.CodFiscale)
Interrogazione 7, altra sol. (passaggio di binding) select * from Persona P where (Nome,Cognome) not in (select P1.Nome, P1.Cognome from Persona P1 where P1.Nome=P.Nome and P1.Cognome=P.Cognome and P1.CodFiscale<>P.CodFiscale)
Interrogazione 8 (passaggio di binding) Data: Cantante(Nome, Canzone) e Autore(Nome,Canzone), estrarre i cantanti che hanno cantato solo canzoni di cui erano autori (cioè i cantautori puri) select Nome from Cantante where Nome not in (select Nome from Cantante C where Nome not in (select Nome from Autore Non cantautore puro where Autore.Canzone=C.Canzone))
Procedure e Trigger (stored) procedure e trigger permettono di implementare funzioni e controlli sui dati, direttamente nella base di dati Il codice SQL (dichiarativo) è arricchito con istruzioni procedurali La sintassi non è standardizzata, per cui ogni DBMS può presentare proprie personalizzazioni
Procedure e Trigger Le procedure permettono di creare uno strato di astrazione sulla rappresentazione delle informazioni strutturate nel database Si possono sollevare le applicazioni da interventi troppo di dettaglio sulla struttura dei dati (e.g. verifiche di consistenza, aggiornamento di informazioni, ecc..) Le stored procedure sono più efficienti di un equivalente programma client
Procedure e Trigger I trigger sono procedure attivabili automaticamente al verificarsi di uno specifico evento Gli eventi gestibili con trigger sono: inserimenti, aggiornamenti e cancellazioni di una tabella Bisogna fare attenzione affinché un trigger non attivi altri trigger in cascata con il rischio di generare dei loop
Procedure e Trigger Istruzioni dichiarative: sono le istruzioni SQL con eventuali estensioni per la gestione di variabili Istruzioni procedurali: costrutti analoghi a quelli normalmente usati nei linguaggi di programmazione If-then-else, while-do, ecc SET TERM <carattere1> <carattere2>
create procedure CREATE PROCEDURE name [(param <datatype> [, param <datatype> ])] [RETURNS (param <datatype> [, param <datatype> ])] AS <procedure_body> [terminator] <procedure_body> = [<variable_declaration_list>] <block> <variable_declaration_list> = DECLARE VARIABLE var <datatype>; [DECLARE VARIABLE var <datatype>; ] <block> = BEGIN <compound_statement> [<compound_statement> ] END
create trigger CREATE TRIGGER name FOR tabella {BEFORE AFTER } {INSERT DELETE UPDATE} AS <trigger_body> Il trigger verrà eseguito prima o dopo un operazione di inserimento/aggiornamento/cancellazione della tabella citata nella clausola FOR Il corpo del trigger può contenere una qualunque istruzione definita anche per le procedure Un trigger NON può ritornare valori
create exception CREATE EXCEPTION name messaggio di errore Un trigger può sollevare un eccezione impedendo l esecuzione degli aggiornamenti relativi L eccezione deve essere precedentemente dichiarata
create generator CREATE GENERATOR name Un generatore è un contatore inizializzato in fase di creazione. Si incrementa ogni volta che viene invocato e garantisce l assegnazione di chiavi univoche Si può invocare con la funzione GEN_ID(generatore, step) con la quale si specifica anche il passo di incremento del contatore stesso
Variante a select SELECT... FROM... WHERE... INTO :variable [, :variable] Le variabili citate nella clausola INTO devono essere state precedentemente dichiarate (declare variable)
for FOR SELECT... FROM... WHERE... INTO :variable [, :variable] DO BEGIN... END Si eseguono tanti cicli di loop quante sono le tuple estratte dalla select
if then else / while do IF (condizione) THEN BEGIN... END [ELSE BEGIN... END] WHILE (condizione) DO BEGIN... END
esempio SET TERM!! ; CREATE PROCEDURE incrementa_stipendi AS DECLARE VARIABLE ID INTEGER; DECLARE VARIABLE STIP INTEGER; DECLARE VARIABLE MEDIA INTEGER; BEGIN SELECT AVG(STIP) FROM IMPIEGATO INTO :MEDIA FOR SELECT IDIMPIEGATO, STIPENDIO FROM IMPIEGATO INTO :ID,:STIP DO BEGIN IF (STIP<MEDIA) THEN UPDATE IMPIEGATO SET STIPENDIO=:MEDIA WHERE IDIMPIEGATO=:ID; END END!! SET TERM ;!!
esempio La procedura può ritornare un insieme di tuple. Per fare ciò è necessario dichiarare una variabile di ritorno per ogni attributo di riga ed eseguire il comando SUSPEND per ogni riga SET TERM!! ; CREATE PROCEDURE stipendixreparto (ID INTEGER) RETURNS (NOME VARCHAR(20), STIP INTEGER) AS BEGIN FOR SELECT NOME, STIPENDIO FROM IMPIEGATO WHERE IDREPARTO=:ID INTO :NOME,:STIP DO BEGIN SUSPEND END END!! SET TERM ;!!
invocazione di procedura Una procedura può essere richiamata da un altra procedura o da un trigger con la seguente sintassi: EXECUTE PROCEDURE procedura [(parametro tipo,...)] [RETURNING_VALUES (risultato)] Se la procedura restituisce dei valori essi vanno assegnati ad altrettante variabili tramite la clausola returning_values (ovviamente i trigger non possono essere invocati essi sono attivati automaticamente dal DBMS)
Transazione Insieme di operazioni da considerare indivisibile ("atomico"), corretto anche in presenza di concorrenza e con effetti definitivi Proprietà ("acide"): Atomicità Consistenza Isolamento Durabilità (persistenza)
Le transazioni sono atomiche La sequenza di operazioni sulla base di dati: o viene eseguita per intero o non viene eseguita affatto: trasferimento di fondi da un conto A ad un conto B: o si fanno il prelevamento da A e il versamento su B o nessuno dei due
Le transazioni sono consistenti Al termine dell'esecuzione di una transazione, i vincoli di integrità debbono essere soddisfatti "Durante" l'esecuzione ci possono essere violazioni, ma alla fine: o sono risolte oppure la transazione deve essere annullata per intero ("abortita")
Le transazioni sono isolate L'effetto di transazioni concorrenti deve essere coerente (ad esempio "equivalente" all'esecuzione separata) se due assegni emessi sullo stesso conto corrente vengono incassati contemporaneamente si deve evitare di trascurarne uno
I risultati delle transazioni sono durevoli La conclusione positiva di una transazione corrisponde ad un impegno (in inglese commit) a mantenere traccia del risultato in modo definitivo, anche in presenza di guasti e di esecuzione concorrente
Transazioni in SQL Una transazione inizia al primo comando SQL dopo la "connessione" alla base di dati oppure alla conclusione di una precedente transazione (lo standard indica anche un comando start transaction (set transaction in firebird), non obbligatorio, e quindi non previsto in molti sistemi) Conclusione di una transazione commit [work]: le operazioni specificate a partire dall'inizio della transazione vengono eseguite sulla base di dati rollback [work]: si rinuncia all'esecuzione delle operazioni specificate dopo l'inizio della transazione Molti sistemi prevedono una modalità autocommit, in cui ogni operazione forma una transazione
Una transazione in SQL start transaction update ContoCorrente set Saldo = Saldo 10 where NumeroConto = 12345 ; update ContoCorrente set Saldo = Saldo + 10 where NumeroConto = 55555 ; commit work; (opzionale)