Annalisa Franco, Dario Maio Università Di Bologna
Annalisa Franco, Dario Maio Università Di Bologna
2
SQL: standard e dialetti
Il processo di standardizzazione di SQL è iniziato nel 1986.
Nel 1992 è stato definito lo standard SQL-2 (o SQL-92) da parte dell’ISO
(International Standards Organization), e dell’ANSI (American National
Standards Institute), rispettivamente descritti nei documenti ISO/IEC
9075:1992 e ANSI X3.135-1992.
Del 1999 è attivo lo standard SQL:1999 che rende SQL un linguaggio
computazionalmente completo (e quindi con istruzioni di controllo!) per il
supporto di oggetti persistenti.
Sono stati rilasciati altri standard nel 2003, 2006 e 2008. A seguito delle
novità introdotte negli ultimi anni, SQL si sta trasformando in un linguaggio
sempre più procedurale.
Allo stato attuale ogni sistema ha ancora un suo dialetto che:
è compatibile (in larga parte) con SQL-2;
ha già elementi degli standard successivi;
ha anche costrutti non standard.
3
Gli standard SQL
Year Name Comments
1992 SQL-92 Major revision (ISO 9075), Entry Level SQL-92 adopted as FIPS 127-2.
Added regular expression matching, recursive queries, triggers, support for procedural and control-
1999 SQL:1999
of-flow statements, non-scalar types, and some object-oriented features.
Introduced XML-related features, window functions, standardized sequences, and columns with auto-
2003 SQL:2003
generated values (including identity-columns).
ISO/IEC 9075-14:2006 defines ways in which SQL can be used in conjunction with XML. It defines
ways of importing and storing XML data in an SQL database, manipulating it within the database
2006 SQL:2006 and publishing both XML and conventional SQL-data in XML form. In addition, it enables applications
to integrate into their SQL code the use of XQuery, the XML Query Language published by the World
Wide Web Consortium (W3C), to concurrently access ordinary SQL-data and XML documents.
Legalizes ORDER BY outside cursor definitions. Adds INSTEAD OF triggers. Adds the TRUNCATE
2008 SQL:2008
statement.
Adds temporal data (PERIOD FOR) (more information at: Temporal database#History). Enhancements
2011 SQL:2011
for window functions and FETCH clause.
2016 SQL:2016 Adds row pattern matching, polymorphic table functions, JSON.
4
http://en.wikipedia.org/wiki/SQL
Data Definition Language (DDL)
5
Creazione ed eliminazione di tabelle
7
I domini
8
Vincoli (1)
Valori di default e valori NULL:
Per vietare la presenza di valori nulli, è sufficiente imporre il vincolo NOT NULL:
Cognome varchar(60) NOT NULL
Per ogni attributo è inoltre possibile specificare un valore di default:
Ruolo char(20) DEFAULT 'Programmatore'
Chiavi:
La definizione di una chiave avviene esprimendo un vincolo UNIQUE, che si può
specificare in linea, se la chiave consiste di un singolo attributo:
CF char(16) UNIQUE
o dopo aver dichiarato tutti gli attributi, se la chiave consiste di uno o più attributi:
UNIQUE(Cognome,Nome)
PRIMARY KEY definisce la chiave primaria:
CodImp char(4) PRIMARY KEY
la specifica di una chiave primaria non è obbligatoria;
si può specificare al massimo una chiave primaria per tabella;
non è necessario specificare NOT NULL per gli attributi della primary key.
9
Vincoli (2)
Chiavi straniere (“foreign key”)
La definizione di una foreign key avviene specificando un vincolo
FOREIGN KEY, e indicando quale chiave viene referenziata;
le colonne di destinazione devono essere una chiave della tabella
destinazione (non necessariamente la chiave primaria):
FOREIGN KEY (Sede) REFERENCES Sedi(Sede)
Vincoli generici (“check constraint”)
Mediante la clausola CHECK è possibile esprimere vincoli di tupla
arbitrari, sfruttando tutto il potere espressivo di SQL. La sintassi è:
CHECK (<condizione>)
Il vincolo è violato se esiste almeno una tupla che rende falsa la
<condizione> (esclusi i valori NULL):
Stipendio int CHECK (Stipendio > 0)
Se CHECK viene espresso a livello di tabella (anziché nella definizione
dell’attributo) è possibile fare riferimento a più attributi della tabella
stessa:
CHECK (ImportoLordo = Netto + Ritenute)
10
Politiche di “reazione”
Anziché lasciare al programmatore il compito di garantire che siano rispettati
i vincoli di integrità referenziale a fronte di cancellazioni e modifiche, si
possono specificare opportune politiche di reazione in fase di definizione
degli schemi.
CREATE TABLE Impiegati (
CodImp char(4) PRIMARY KEY,
Sede char(3),
...
FOREIGN KEY Sede REFERENCES Sedi
ON DELETE CASCADE -- cancellazione in cascata
ON UPDATE NO ACTION -- modifiche non permesse
11
DB di riferimento per gli esempi
Impiegati Sedi
CodImp Nome Sede Ruolo Stipendio Sede Responsabile Città
E001 Rossi S01 Analista 2000 S01 Biondi Milano
E002 Verdi S02 Sistemista 1500 S02 Mori Bologna
E003 Bianchi S01 Programmatore 1000 S03 Fulvi Milano
12
L’istruzione SELECT
È l’istruzione che permette di eseguire interrogazioni (query) sul DB.
SELECT [ALL|DISTINCT][TOP(n)[PERCENT][WITH TIES]]
A1,A2,..,Am
FROM R1,R2,..,Rn
[WHERE <condizione>]
[GROUP BY <listaAttributi>]
[HAVING <condizione>]
[ORDER BY <listaAttributi>]
ovvero:
SELECT (o TARGET) list (che cosa si vuole come risultato)
clausola FROM (da dove si prende)
clausola WHERE (quali condizioni deve soddisfare)
clausola GROUP BY (le colonne su cui raggruppare)
clausola HAVING (condizioni relative ai gruppi)
clausola ORDER BY (ordinamento)
14
Selezione e proiezione in SQL
15
SELECT senza proiezione
SELECT *
FROM Impiegati
WHERE Sede = 'S01'
16
SELECT senza selezione (condizione)
SELECT *
FROM Impiegati
17
Tabelle vs Relazioni: la clausola DISTINCT
18
La clausola TOP
La clausola TOP specifica quante righe deve restituire, come risultato, la query.
L’insieme di righe da restituire può essere specificato come numero o come valore
percentuale.
È possibile mantenere più record se hanno lo stesso valore per uno o più attributi (WITH
TIES).
19
La clausola TOP: esempi
CodImp Nome
SELECT CodImp, Nome E001 Rossi
20
Espressioni complesse
All’interno di un comando SELECT è
possibile inserire espressioni booleane con
operatori AND e OR e NOT:
SELECT Nome
Nome Sede Ruolo
FROM Impiegati Rossi S01 Analista
WHERE Sede = 'S01' Verdi S02 Sistemista
OR Ruolo = 'Programmatore' Bianchi S01 Programmatore
Gialli S03 Programmatore
SELECT Nome
Neri S02 Analista
FROM Impiegati
Grigi S01 Sistemista
WHERE Sede = 'S01'
Violetti S01 Programmatore
AND Ruolo = 'Programmatore' Aranci S02 Programmatore
21
Operatore BETWEEN
L’operatore BETWEEN permette di esprimere condizioni di appartenenza a un
intervallo:
Nome e stipendio degli impiegati che hanno uno stipendio compreso tra
1300 e 2000 Euro (estremi inclusi)
Nome Stipendio
Rossi 2000
Verdi 1500
Lo stesso risultato si ottiene anche come segue:
SELECT Nome, Stipendio
FROM Impiegati
WHERE Stipendio >= 1300 AND Stipendio <= 2000
22
Operatore IN
L’operatore IN permette di esprimere condizioni di appartenenza a un
insieme:
Codici e sedi degli impiegati delle sedi S02 e S03
23
Operatore LIKE
24
Espressioni nella clausola SELECT
25
Ridenominazione delle colonne
A ogni elemento della SELECT list è possibile associare un nome a piacere:
26
Pseudonimi
Per chiarezza ogni nome di colonna può essere scritto aggiungendo ad esso, come
prefisso, il nome della tabella (obbligatorio in caso di ambiguità):
…e si può anche usare uno pseudonimo (alias) in luogo del nome della tabella
27
Valori nulli
Il trattamento dei valori nulli si basa su quanto già visto in algebra relazionale,
quindi la query:
Impiegati
SELECT CodImp
CodImp Sede … Stipendio
FROM Impiegati E001 S01 2000
WHERE Stipendio > 1500 E002 S02 1500
OR Stipendio <= 1500 E003 S01 1000
E004 S03 NULL
CodImp
restituisce solo E001
E005 S02 2500
E007
E008
28
Logica a 3 valori in SQL
Nel caso di espressioni complesse, SQL ricorre alla logica a 3 valori: vero (V),
falso (F) e “sconosciuto” (?).
SELECT CodImp, Sede, Stipendio CodImp Sede Stipendio
FROM Impiegati E001 S01 2000
WHERE (Sede = 'S03') E004 S03 NULL
CodImp
SELECT CodImp E004
FROM Impiegati E006
30
Ordinamento e clausola TOP
Può essere molto utile usare la clausola TOP in combinazione con ORDER BY.
Nome dell’impiegato con ruolo 'Programmatore' che
percepisce lo stipendio più basso
SELECT TOP(1) Nome, Stipendio
FROM Impiegati Nome Stipendio
WHERE Ruolo = 'Programmatore' Bianchi 1000
ORDER BY Stipendio
N.B. WITH TIES si può usare solo in presenza di ORDER BY e i “pareggi” (TIES) si
riferiscono alla combinazione degli attributi di ordinamento.
31
Interrogazioni su più tabelle
L’interrogazione
32
Interrogazioni su più tabelle: risultato
Dopo avere applicato il predicato I.Sede = S.Sede:
33
Ridenominazione del risultato
Se la SELECT list contiene 2 o più colonne con lo stesso nome, è necessario
operare una ridenominazione per ottenere un risultato in output con tutte le
colonne dotate di intestazione:
SedeE001 AltraSede
S01 S02
S01 S03
34
Self Join
L’uso di alias è forzato quando si deve eseguire un self-join:
Genitori G1 Genitori G2
Genitore Figlio Genitore Figlio
Luca Anna Luca Anna
Chi sono i nonni di Anna? Maria Anna Maria Anna
Giorgio Luca Giorgio Luca
Silvia Maria Silvia Maria
Enzo Maria Enzo Maria
35
Join espliciti
36
Outer join: esempi
Per ciascuna sede visualizzare il nome del responsabile e il
numero di Analisti che vi lavorano.
COUNT(I.CodImp)
È importante applicare il count a un
attributo di Impiegati per ottenere un valore
0 per le sedi senza analisti
37
Operatori insiemistici
L’istruzione SELECT non permette di eseguire unione, intersezione e differenza
di tabelle.
Ciò che si può fare è combinare in modo opportuno i risultati di due istruzioni
SELECT, mediante gli operatori:
In tutti i casi gli elementi delle SELECT list devono avere tipi compatibili e gli
stessi nomi se si vogliono colonne con un’intestazione definita.
L’ordine degli elementi è importante (notazione posizionale).
Il risultato è in ogni caso privo di duplicati, per mantenerli occorre aggiungere
l’opzione ALL:
R A B S C B B
SELECT A SELECT B
1 a 1 a
FROM R 1 FROM R a
1 a 1 b
UNION 2 UNION ALL a
2 a 2 a a
SELECT C 3 SELECT B
2 b 2 c
FROM S 4 FROM S b
2 c 3 c c
3 b 4 d b
SELECT A,B a
A
FROM R b
SELECT A
UNION a
FROM R 1
2 SELECT B,C AS A c
UNION
FROM S c
SELECT C AS A 3
d
FROM S 4 Non corretta!
39
Operatori insiemistici: esempi (2)
R A B
1 a SELECT B B SELECT B B
1 a FROM R a FROM S d
2 a INTERSECT b EXCEPT
2 b SELECT B c SELECT B
2 c FROM S FROM R
3 b
S C B B B
SELECT B SELECT B
1 a
FROM R a FROM R a
1 b
INTERSECT ALL a EXCEPT ALL b
2 a b
SELECT B SELECT B
2 c FROM S c FROM S
3 c
4 d
40
Istruzioni di aggiornamento dei dati
Le istruzioni che permettono di aggiornare il DB sono:
41
Inserimento di tuple: caso singolo
È possibile inserire una nuova tupla specificandone i valori:
INSERT INTO Sedi(Sede, Responsabile, Città)
VALUES ('S04','Bruni','Firenze')
42
Inserimento di tuple: caso multiplo
Gli schemi del risultato e della tabella in cui si inseriscono le tuple possono
essere diversi, ma è necessario rispettare che i tipi delle colonne siano
compatibili.
43
Cancellazione e modifica di tuple
L’istruzione DELETE può fare uso di una condizione per specificare le tuple da
cancellare:
DELETE FROM Sedi -- elimina le sedi di Bologna
WHERE Città = 'Bologna'
Anche l’istruzione UPDATE può fare uso di una condizione, per specificare le
tuple da modificare, e di espressioni per determinare i nuovi valori:
UPDATE Sedi
SET Responsabile = 'Bruni',
Città = 'Firenze‘
WHERE Sede = 'S01'
UPDATE Impiegati
SET Stipendio = 1.1*Stipendio
WHERE Ruolo = 'Programmatore'
44
Data Manipulation Language (DML)
INSERT può usare il risultato di una query per eseguire inserimenti multipli.
45
Il linguaggio SQL: raggruppamenti
Informazioni di sintesi
Quanto sinora visto permette di estrarre dal DB informazioni che si riferiscono a
singole tuple (eventualmente ottenute mediante operazioni di join).
Esempio: il ruolo dell’impiegato 'E001', il responsabile della sede 'S02', il
ruolo degli impiegati della sede 'S01', ecc.
In molti casi è viceversa utile ottenere dal DB informazioni (di sintesi) che
caratterizzano “gruppi” di tuple.
Esempio: il numero di programmatori della sede 'S01', la media degli stipendi a
Bologna, ecc.
47
Funzioni aggregate (1)
Lo standard SQL mette a disposizione una serie di funzioni
aggregate (o “di colonna”):
MIN minimo;
MAX massimo;
SUM somma;
AVG media aritmetica;
STDEV deviazione standard;
VARIANCE varianza;
COUNT contatore.
48
Funzioni aggregate (2)
L’argomento di una funzione aggregata è una qualunque espressione che
può figurare nella SELECT list (ma NON UN’ALTRA FUNZIONE
AGGREGATA!)
49
COUNT e valori nulli
La forma COUNT(*) conta le tuple del risultato; viceversa, specificando una
colonna, si omettono quelle con valore nullo in tale colonna:
SELECT COUNT(*) AS NumImpS01
Impiegati FROM Impiegati
CodImp Sede … Stipendio WHERE Sede = 'S01'
NumImpS01
E001 S01 2000 4
E002 S02 1500
E003 S01 1000
SELECT COUNT(Stipendio)
E004 S03 NULL
AS NumStipS01
E005 S02 2500
FROM Impiegati
E006 S01 NULL
E007 S01 1000
WHERE Sede = 'S01' NumStipS01
50
Funzioni aggregate e tipo del risultato
Per alcune funzioni aggregate, al fine di ottenere il risultato desiderato, è
necessario operare un casting dell’argomento:
Impiegati
SELECT AVG(Stipendio) AS AvgStip
… Stipendio
2000 FROM Impiegati -- valore esatto 1412.5
1500 AvgStip
1000 1412
1000
2500
SELECT AVG(CAST(Stipendio AS Decimal(6,2)))
1100 AS AvgStip
1000
FROM Impiegati AvgStip
1200
1412.50
51
Clausola SELECT e funzioni aggregate
Se si usano funzioni aggregate, la SELECT list non può includere altri elementi
che non siano a loro volta funzioni aggregate:
non va bene!
(viceversa, SELECT MIN(Stipendio), MAX(Stipendio).. è corretto)
53
Come si ragiona con il GROUP BY
54
GROUP BY: esempi
1) Per ogni ruolo, lo stipendio medio nelle sedi di Milano
Ruolo AvgStip
SELECT I.Ruolo, AVG(I.Stipendio) AS AvgStip
Analista 2000
FROM Impiegati I JOIN Sedi S ON (I.Sede = S.Sede)
Sistemista 1100
WHERE S.Città = 'Milano'
Programmatore 1000
GROUP BY I.Ruolo
equivale pertanto a:
56
Condizioni sui gruppi
Oltre a poter formare dei gruppi, è anche possibile selezionare alcuni
gruppi sulla base di loro proprietà “complessive”:
57
Tipi di condizioni sui gruppi
Nella clausola HAVING si possono avere due tipi di predicati:
predicati che fanno uso di funzioni aggregate (es. COUNT(*)> 2);
predicati che si riferiscono alle colonne di raggruppamento; questi ultimi si
possono anche inserire nella clausola WHERE.
Per ogni sede di Bologna in cui il numero di impiegati è almeno 3, si vuole conoscere il
valor medio degli stipendi, ordinando il risultato per valori decrescenti di stipendio
medio e quindi per sede
59
Il linguaggio SQL: query innestate
Subquery
Oltre alla forma “flat” vista sinora, in SQL è anche possibile esprimere condizioni
che si basano sul risultato di altre interrogazioni (subquery, o query innestate o
query nidificate):
61
Subquery scalari
Gli operatori di confronto =, <,… si possono usare solo se la subquery
restituisce non più di una tupla (subquery “scalare”):
SELECT Responsabile
FROM Sedi
WHERE Sede = (SELECT Sede -- al massimo una sede
FROM Impiegati Sede
WHERE CodImp = 'E001') S01
62
Subquery: caso generale
Se la subquery può restituire più di un valore si devono usare le forme:
<op> ANY: la relazione <op> vale per almeno uno dei valori;
<op> ALL: la relazione <op> vale per tutti i valori.
SELECT Responsabile
FROM Sedi
WHERE Sede = ANY (SELECT Sede
FROM Impiegati
WHERE Stipendio > 1500)
63
Subquery: livelli multipli di innestamento
Una subquery può fare uso a sua volta di altre subquery. Il risultato si può
ottenere risolvendo a partire dal blocco più interno:
SELECT CodImp
FROM Impiegati
WHERE Sede IN (SELECT Sede
FROM Sedi
WHERE Città NOT IN (SELECT Città
FROM Prog
WHERE CodProg = 'P02'))
Attenzione a non sbagliare quando ci sono negazioni! Nell’esempio, i due blocchi interni
NON sono equivalenti a:
WHERE Sede IN (SELECT Sede
FROM Sedi, Prog
WHERE Sedi.Città <> Prog.Città
AND Prog.CodProg = 'P02')
64
Subquery: quantificatore esistenziale
Mediante EXISTS (SELECT * …) è possibile verificare se il risultato di una
subquery restituisce almeno una tupla:
SELECT Sede
FROM Sedi S
WHERE EXISTS (SELECT *
FROM Impiegati
WHERE Ruolo = 'Programmatore')
65
Subquery correlate
Se la subquery fa riferimento a “variabili” definite in un blocco esterno, allora si
dice che è correlata:
66
Subquery: “unnesting” (1)
È spesso possibile ricondursi a una forma “piatta”, ma la cosa non è sempre così
ovvia. Ad esempio, l’interrogazione precedente si può anche scrivere:
SELECT DISTINCT Sede
FROM Sedi S, Impiegati I
WHERE S.Sede = I.Sede
AND I.Ruolo = 'Programmatore'
67
Subquery: “unnesting” (2)
Con la negazione le cose tendono a complicarsi. Ad esempio, per trovare le sedi senza
programmatori, nella forma innestata basta sostituire NOT EXISTS a EXISTS,
Sede
SELECT Sede -- sedi senza programmatori
S04
FROM Sedi S
WHERE NOT EXISTS (SELECT *
FROM Impiegati
WHERE Ruolo = 'Programmatore'
AND Sede = S.Sede)
ma la forma piatta: Sede
S01
SELECT DISTINCT Sede
S02
FROM Sedi S JOIN Impiegati I ON (S.Sede = I.Sede)
S03
WHERE I.Ruolo <> 'Programmatore'
S04
restituisce le sedi in cui lavora almeno un impiegato
con ruolo diverso da un programmatore.
68
Subquery: “unnesting” (3)
Una soluzione “piatta” corretta (ma complessa) è:
il join restituisce come risultato le sedi con relativi impiegati nel ruolo programmatore comprese
le sedi senza programmatori;
la clausola WHERE seleziona solo queste ultime.
il join restituisce come risultato le sedi con relativi impiegati (di qualsiasi ruolo) comprese le sedi
senza impiegati;
la clausola WHERE non è mai soddisfatta!
69
Un esempio complesso
Sede che ha il numero maggiore di impiegati con ruolo 'Programmatore'
SELECT Sede, COUNT(CodImp) AS NumProg
FROM Impiegati I1
WHERE I1.Ruolo = 'Programmatore' Sede NumProg
GROUP BY I1.Sede S01 2
HAVING COUNT(CodImp) >= ALL
(SELECT COUNT(CodImp)
FROM Impiegati I2
WHERE I2.Ruolo = 'Programmatore'
GROUP BY I2.Sede)
SELECT TOP(1) WITH TIES Sede, COUNT(CodImp)
FROM Impiegati
In alternativa… WHERE Ruolo = 'Programmatore'
GROUP BY Sede
ORDER BY COUNT(CodImp) DESC
N.B. molte query innestate non possono essere semplificate usando la clausola TOP
(es. impiegati che hanno uno stipendio superiore a quello medio per il relativo ruolo).
70
Subquery: come eseguire la divisione
Con le subquery è possibile eseguire la divisione relazionale.
“Sedi in cui sono presenti tutti i ruoli”
equivale a
“Sedi in cui non esiste un ruolo non presente”
SELECT Sede
FROM Sedi S
WHERE NOT EXISTS (SELECT Ruolo
FROM Impiegati I1
Sede WHERE NOT EXISTS
S01 (SELECT *
S02 FROM Impiegati I2
WHERE S.Sede = I2.Sede
AND I1.Ruolo = I2.Ruolo))
72
La divisione: il semplice conteggio non è sempre
possibile
L’espressione “Sedi in cui sono presenti tutti i ruoli della sede 'S03‘ ” NON
equivale a “Sedi per cui il numero di ruoli distinti è uguale al numero di ruoli
presenti nella sede 'S03' ”.
Occorre imporre un vincolo: solo ruoli presenti in 'S03'.
SELECT Sede FROM Impiegati I
WHERE Ruolo IN (SELECT Ruolo
FROM Impiegati I2
WHERE Sede = 'S03')
GROUP BY Sede
HAVING COUNT (DISTINCT Ruolo) =
(SELECT COUNT (DISTINCT Ruolo)
Sede FROM Impiegati
S01 WHERE Sede = 'S03')
Sede
S02 invece, senza condizione… S03
S03 S04
73
Subquery: aggiornamento dei dati
Le subquery si possono efficacemente usare per aggiornare i dati di una tabella
sulla base di criteri che dipendono dal contenuto di altre tabelle:
Supponendo di avere due tabelle ImpBO e ImpMI e di volere che uno stesso
codice (CodImp) non sia presente in entrambe le tabelle:
75
Il linguaggio SQL: viste e tabelle derivate
Definizione di viste
Mediante l’istruzione CREATE VIEW si definisce una vista, ovvero una “tabella
virtuale”.
Le tuple della vista sono il risultato di una query che viene valutata
dinamicamente ogni volta che si fa riferimento alla vista.
ProgSedi
77
Uso delle viste
Le viste possono essere create a vari scopi, tra i quali si ricordano i seguenti:
permettere agli utenti di avere una visione personalizzata del DB che in
parte astragga dalla struttura logica del DB stesso;
far fronte a modifiche dello schema logico che comporterebbero una
ricompilazione dei programmi applicativi;
semplificare la scrittura di query complesse.
Inoltre le viste possono essere usate come meccanismo per il controllo degli
accessi, fornendo a ogni classe di utenti gli opportuni privilegi.
Si noti che nella definizione di una vista si possono referenziare anche altre
viste.
78
Indipendenza logica tramite VIEW
A titolo esemplificativo si consideri un DB che contiene la tabella
EsamiBD(Matr,Cognome,Nome,DataProva,Voto)
79
Query complesse che usano VIEW
SELECT I.Sede
FROM Impiegati I
GROUP BY I.Sede
HAVING COUNT(*) >= ALL (SELECT COUNT(*)
FROM Impiegati I1
GROUP BY I1.Sede)
80
Query complesse che usano VIEW
La soluzione con viste è:
NumImp
Sede NImp
CREATE VIEW NumImp(Sede,Nimp)
S01 4
AS SELECT Sede, COUNT(*)
S02 3
FROM Impiegati
GROUP BY Sede S03 1
SELECT Sede
FROM NumImp
WHERE Nimp = (SELECT MAX(NImp)
FROM NumImp)
che permette di trovare “il MAX dei COUNT(*)”, cosa che, si ricorda, non
si può fare direttamente scrivendo MAX(COUNT(*)).
81
Aggiornamento di viste
Le viste possono essere utilizzate per le interrogazioni come se fossero
tabelle del DB, ma per le operazioni di aggiornamento ci sono dei limiti.
UPDATE NumImp
SET NImp = NImp + 1
WHERE Sede = 'S03'
82
Aggiornabilità di viste (1)
Una vista è di fatto una funzione che calcola un risultato y a partire da
un’istanza di database r, y = V(r).
L’aggiornamento di una vista, che trasforma y in y’, può essere eseguito se e
solo se è univocamente definita la nuova istanza r’ tale che y’ = V(r’), e ciò
corrisponde a dire che la vista è “invertibile”, ossia r’ = V-1(y’) .
Data la complessità del problema, di fatto ogni DBMS pone dei limiti sulle
tipologie di viste che possono essere aggiornate.
Le più comuni restrizioni riguardano la non aggiornabilità di viste in cui il
blocco più esterno della query di definizione contiene:
GROUP BY;
funzioni aggregate;
DISTINCT;
83
Aggiornabilità di viste (2)
La precisazione che è il blocco più esterno della query di definizione che non deve
contenere, ad es., dei join ha importanti conseguenze.
Ad esempio, la vista:
CREATE VIEW ImpBO(CodImp,Nome,Sede,Ruolo,Stipendio)
AS SELECT I.*
FROM Impiegati I JOIN Sedi S ON (I.Sede = S.Sede)
WHERE S.Città = 'Bologna'
84
Viste con CHECK OPTION
Per le viste aggiornabili si presenta un nuovo problema. Si consideri il seguente
inserimento nella vista ImpBO:
in cui il valore di Sede ('S03') non rispetta la specifica della vista. Ciò
comporta che una successiva query su ImpBO non restituirebbe la tupla
appena inserita (!?).
Per evitare situazioni di questo tipo, all’atto della creazione di una vista si può
specificare, facendola seguire alla query che definisce la vista, la clausola
WITH CHECK OPTION, che garantisce che ogni tupla inserita nella vista sia
anche restituita dalla vista stessa.
85
Tipi di CHECK OPTION
Se la vista V1 è definita in termini di un’altra vista V2, e si specifica la clausola
WITH CHECK OPTION, il DBMS verifica che la nuova tupla t inserita
soddisfi sia la definizione di V1 sia quella di V2, indipendentemente dal fatto
che V2 sia stata a sua volta definita WITH CHECK OPTION.
86
Table expressions
Tra le caratteristiche più interessanti di SQL vi è la possibilità di usare
all’interno della select list o della clausola FROM una subquery che definisce
“dinamicamente” una tabella derivata, e che qui viene anche detta “table
expression”.
oppure…
88
Table expressions correlate (2)
89
Limiti delle table expressions
Si consideri la query:
la sede in cui la somma degli stipendi è massima
La soluzione con table expressions è:
SELECT Sede
FROM (SELECT Sede, SUM(Stipendio) AS TotStip
FROM Impiegati
GROUP BY Sede) AS SediStip
WHERE TotStip = (SELECT MAX(TotStip)
FROM
(SELECT Sede, SUM(Stipendio) AS TotStip
FROM Impiegati
GROUP BY Sede) AS SediStip2)
Benché la query sia corretta, non è sfruttato il fatto che le due table
expressions sono identiche, e ciò porta a una valutazione inefficiente e a una
formulazione poco leggibile.
90
Common table expressions
L’idea alla base delle “common table expressions” è definire una “vista
temporanea” che può essere usata in una query come se fosse a tutti gli effetti
una VIEW:
SELECT Sede
FROM SediStip
WHERE TotStip = (SELECT MAX(TotStip)
FROM SediStip)
91
WITH e interrogazioni ricorsive (1)
Si consideri la tabella Genitori(Figlio,Genitore) e la query
WITH Antenati(Persona,Avo)
AS (
(SELECT Figlio, Genitore -- subquery base
FROM Genitori)
UNION ALL -- sempre UNION ALL!
(SELECT G.Figlio, A.Avo -- subquery ricorsiva
FROM Genitori G, Antenati A
WHERE G.Genitore = A.Persona)
)
SELECT Avo
FROM Antenati
WHERE Persona = ‘Anna’
93
WITH e interrogazioni ricorsive (3)
Per comprendere meglio come funziona la valutazione di una query ricorsiva,
e come “ci si ferma”, si tenga presente che a ogni iterazione il DBMS
aggiunge ad Antenati le tuple che risultano dal join tra Genitori e le
sole tuple aggiunte ad Antenati al passo precedente:
Genitori Antenati
Figlio Genitore subquery base Persona Avo
Anna Luca Anna Luca
Luca Maria subquery ricorsiva Luca Maria
Luca Giorgio Luca Giorgio
Giorgio Lucia Giorgio Lucia
Anna Maria
Anna Giorgio
Luca Lucia
Anna Lucia
94
Uso delle common table expressions
Per le subquery ricorsive vi sono alcune restrizioni, tra cui va ricordato che
non si possono usare funzioni aggregate, GROUP BY e SELECT DISTINCT.
95
Domande?
96