Programma del Corso di Basi di Dati

Interrogazioni di tipo insiemistico
SQL fornisce anche gli operatori di tipo insiemistico
union,
intersect,
except (minus)
con la seguente sintassi:
SelectSQL
{< union|intersect|except >[all]} SelectSQL
• intersect e except potrebbero anche essere derivati
attraverso opportune query
• gli operatori insiemistici eseguono per default una
eliminazione dei duplicati; all specifica di non farla
• gli schemi su cui si opera non devono essere identici come
nell’algebra relazionale ma avere uguale numero di attributi
e domini compatibili. La corrispondenza è per posizione.
Interrogazioni di tipo insiemistico
Estrarre nomi e cognomi degli impiegati
select Nome
from Impiegato
union
select Cognome
from Impiegato
Estrarre i cognomi degli impiegati che sono anche nomi
select Nome
from Impiegato
intersect
select Cognome
from Impiegato
Interrogazioni nidificate
Interrogazioni nidificate
E’ possibile anche realizzare clausole where in cui il confronto
non avviene fra predicati semplici o fra valori, ma fra valori e
insiemi di valori, appartenenti allo stesso dominio, che sono
risultato di un’altra interrogazione.
select I.Nome, Cognome
from Impiegato I
where Dipart = any (select D.Nome
from Dipartimento D
where Città=‘Firenze’)
SQL offre 2 possibilità di estendere gli operatori di confronto al
caso del confronto valore/insieme (risultato query):
Il risultato comprende:
all specifica che il risultato del confronto è vero se è vero per
tutte le righe del risultato dell’interrogazione.
tutte le righe di IMPIEGATO per cui il valore Dipart è uguale
ad almeno uno dei valori di Nome in DIPARTIMENTO,
limitatamente alle tuple per cui Città=‘Firenze’,
any specifica che il risultato del confronto è vero se è vero per
una qualunque riga del risultato dell’interrogazione.
cioè
l’elenco degli impiegati che lavorano in dipartimenti con
sede a Firenze.
1
Interrogazioni nidificate
Lo stesso risultato si poteva ottenere con un join, ma così,
specialmente per interrogazioni complesse, è più leggibile.
select I.Nome, Cognome
from Impiegato I
where Dipart = any ( select D.Nome
from
Dipartimento D
where Città = ’Firenze’)
select I.Nome, Cognome
from
Impiegato I, Dipartimento D
where
Dipart = D.Nome
and
Città = ’Firenze’
Interrogazioni nidificate
L’uso delle interrogazioni nidificate può anche eliminare la
necessità degli alias.
Es.
select I1.Nome
from
Impiegato I1, Impiegato I2
where I1.Nome = I2.Nome
and
I1.Dipart = ’Produz’
and
I2.Dipart <> ’Produz’
equivale a
select Nome
from Impiegato
where Nome = any (select I.Nome
from Impiegato I
where I.Dipart=’Produz’)
and Dipart <> ’Produz’
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
Non tutte le interrogazioni nidificate corrispondono però ad un join
select Nome
from
Dipartimento
where Nome <> all ( select Dipart
from Impiegato
where Cognome=‘Rossi’)
La condizione è verificata per le righe che NON contengono un
certo valore, quindi non è esprimibile mediante un join, che
richiede una corrispondenza fra valori. Però è equivalente a :
P Nome(DIPARTIMENTO) - P Dipart (s Cognome=‘Rossi’(IMPIEGATO)))
e quindi le due query potevano essere unite da except
NB: =any e <>all si possono anche scrivere in e not in
2
Operatori aggregati e nidificazione
• La persona (o le persone) con il reddito massimo
select *
from persone
where reddito = ( select max(reddito)
from persone )
Operatori aggregati e nidificazione
select
from
where
Dipart, Stipendio
Impiegato
Stipendio =
( select max(Stipendio)
from Impiegato )
equivale a
select Dipart, Stipendio
from Impiegato
where Stipendio >= all ( select Stipendio
from Impiegato
(n.b. il massimo di un insieme è il valore, appartenente a
quell’insieme, che è maggiore o uguale a tutti gli altri)
Operatori aggregati e nidificazione
Interpretazione delle query nidificate
Attenzione: un operatore aggregato non può essere applicato
ad un altro operatore aggregato.
Ad es., non posso utilizzare max se voglio calcolare il
massimo fra i risultati di un operatore aggregato applicato ai
sottoinsiemi definiti con la clausola group by.
In questo caso è obbligatorio usare un confronto fra valori di
due sottoinsiemi (spesso uguali)
Per analizzare il risultato di una interrogazione nidificata si
può supporre di valutare prima il risultato dell’interrogazione
nidificata e poi quella della interrogazione che la contiene.
select Dipart, sum(Stipendio) as MaxSumSt
from Impiegato
group by Dipart
having MaxSumSt >=all (select sum(Stipendio)
from Impiegato
group by Dipart )
In questo caso bisogna usare la definizione ‘procedurale’ di
query, che calcola il prodotto cartesiano fra le tabelle e poi
verifica la condizione where separatamente per ogni riga.
Questo migliora anche l’efficienza, in quanto l’interrogazione
nidificata viene eseguita una sola volta. Talvolta però esiste
una dipendenza tramite variabile (passaggio di binding) fra
l’interrogazione nidificata e quella che la contiene.
Quindi per ogni riga della query esterna (da cui dipende
anche la query interna) si valuta prima la query nidificata per
poi calcolare il predicato a livello di riga sulla query esterna.
3
Interrogazioni nidificate
Le variabili SQL sono utilizzabili solo nella query in cui sono
definite o nell’ambito di una query nidificata al suo interno.
Se due query sono allo stesso livello non possono
condividere variabili.
exists
è un operatore logico applicabile a query nidificate.
Restituisce vero se la query dà un risultato non nullo, falso
se è nullo.
E’ utilizzabile in modo significativo solo se esiste un
passaggio di binding fra interrogazione esterna e
interrogazione nidificata.
Le persone che hanno almeno un figlio
select *
from Persone P
where exists ( select *
from Paternita
where Padre = P.Nome)
or
exists ( select *
from Maternita
where Madre = P.Nome)
exists
Costruttore di tuple
select *
from Persona P
where exists ( select *
from Persona P1
where P1.Nome = P.Nome
and P1.Cognome = P.Cognome
and P1.Cfiscale <> P.CFiscale)
Quando si deve valutare una condizione che coinvolge un
insieme di attributi, la lista degli attributi coinvolti viene
inserita all’interno di una parentesi tonda.
In questo caso non è possibile eseguire prima la query
nidificata, in quanto è indeterminata se non si risolve il
riferimento. Quindi per ogni riga dell’interrogazione esterna
dovrà essere valutata l’interrogazione nidificata.
Es.
select *
from Persona P
where (Nome, Cognome) in
( select Nome, Cognome
from
Persona Q
where P.CFiscale <> Q.CFiscale)
4