Interrogazioni nidificate-AD8

Query nidificate

L’uso di query nidificate può produrre query ‘meno dichiarative’, ma spesso si migliora la leggibilità. La prima versione di SQL prevedeva solo la forma nidificata (o strutturata) con una sola relazione nella clausola from, il che è insoddisfacente. Le sottointerrogazioni non possono contenere operatori insiemistici (“l’unione si fa solo al livello esterno”); la limitazione non è significativa, ed è superata da alcuni sistemi.
Nella clausola where possono comparire predicati che:
– confrontano un attributo (o un’espressione sugli attributi) con il risultato di una query SQL; sintassi:
AttrExpr Operator < any | all &gt; SelectSQL
• any: il predicato è vero se almeno una riga restituita dalla query SelectSQL soddisfa il confronto
• all: il predicato è vero se tutte le righe restituite dalla query SelectSQL soddisfano il confronto
• Operator: uno qualsiasi tra =, <>, <, <=, >, >=
La query che appare nella clausola where è chiamata query nidificata.

Altre query:

– AttrExpr Operator < in | not in > SelectSQL
in:  il predicato è vero se almeno una riga restituita dalla query SelectSQL e’ presente nell’espressione
Not in: il predicato è vero se nessuna riga restituita query e’ presente nell’espressione
– <exists | not exists> SelectSQL
•exists: il predicato è vero se la query possiede tuple
•not exists: il predicato è vero se la query non possiede tuple

Uso di any e all

 select CodOrd
from Ordine
where Importo > any
select Importo
from Ordine
 select CodOrd
from Ordine
where Importo >= all
select Importo
from Ordine

query nidificate

Query nidificate con any
• Estrarre gli ordini di prodotti con un prezzo superiore a 100
select CodOrd
from Dettaglio
where CodProd = any(select CodProd
from Prodotto
where Prezzo > 100)
• Equivalente a (senza query nidificata)
select CodOrd
from Dettaglio D, Prodotto P
where D.CodProd = P.CodProd
and Prezzo > 100

Query nidificate con any
• Estrarre i prodotti ordinati assieme al prodotto avente codice ‘ABC’
– con una query nidificata:
select CodProd
from Dettaglio
where CodOrd = any
(select CodOrd
from Dettaglio
where CodProd = ’ABC’)
– senza query nidificata, a meno di duplicati:
select D1.CodProd
from Dettaglio D1, Dettaglio D2
where D1.CodOrd = D2.CodOrd and
D2.CodProd = ’ABC’

Negazione con query nidificate

• Estrarre gli ordini che non contengono il prodotto ‘ABC’:

select distinct CodOrd
from Ordine
where CodOrd <> all (select CodOrd

from Dettaglio
where CodProd = ’ABC’)

• In alternativa:

select CodOrd
from Ordine
except
select CodOrd
from Dettaglio
where CodProd = ’ABC’

Operatori in e not in
• L’operatore in è equivalente a = any
select CodProd
from Dettaglio
where CodOrd in
(select CodOrd
from Dettaglio
where CodProd = ’ABC’)
• L’operatore not in è equivalente a <> all
select distinct CodOrd
from Ordine
where CodOrd not in (select CodOrd
from Dettaglio
where CodProd = ’ABC’)

Altro esempio con “in”
• Estrarre nome e indirizzo dei clienti che hanno emesso qualche ordine di importo superiore a 10.000
select Nome, Indirizzo
from Cliente
where CodCli in
select CodCli
from Ordine
where Importo > 10000
Query nidificate a più livelli
Estrarre nome e indirizzo dei clienti che hanno emesso qualche ordine che comprende il prodotto “Pneumatico”
select Nome, Indirizzo
from Cliente
where CodCli in
select CodCli
from Ordine
where CodOrd in
select CodOrd
from Dettaglio
where CodProd in
select CodProd
from Prodotto
where Nome = ’Pneumatico’

La query equivalente
• La query precedente equivale (a meno di duplicati) a:
select C.Nome, Indirizzo
from Cliente as C, Ordine as O,
Dettaglio as D, Prodotto as P
where C.CodCli = O.CodCli
and O.CodOrd = D.CodOrd
and D.CodProd = P.CodProd
and P.Nome = ’Pneumatico’

max con query nidificata
• Gli operatori aggregati max (e min) possono essere espressi tramite query nidificate
• Estrarre l’ordine con il massimo importo
– Con una query nidificata, usando max:
select CodOrd
from Ordine
where Importo in (select max(Importo)
from Ordine)
– con una query nidificata, usando all:
select CodOrd
from Ordine
where Importo >= all (select Importo
from Ordine)

L’operatore exists
• Si può usare il quantificatore esistenziale sul risultato di una query SQL
• Sintassi:
exists SelectStar
• Il predicato è vero se la query SelectStar restituisce un risultato non nullo
(selectStar: si consiglia di usare sempre select * perché è irrilevante la proiezione)

Query nidificate complesse

• La query nidificata può usare variabili della query esterna
– Interpretazione: la query nidificata viene valutata per ogni tupla della query esterna
• Estrarre tutti i clienti che hanno emesso più di un ordine nella stessa giornata:
select CodCli
from Ordine O
where exists (select *
from Ordine O1
where O1.CodCli = O.CodCli
and O1.Data = O.Data
and O1.CodOrd <> O.CodOrd)
Query nidificate complesse
• Estrarre tutte le persone che [non] hanno degli omonimi:
select *
from Persona P
where [not] exists
(select *
from Persona P1
where P1.Nome = P.Nome
and P1.Cognome = P.Cognome
and P1.CodFisc <> P.CodFisc)

Costruttore di tupla

• Il confronto con la query nidificata può coinvolgere più di un attributo
• Gli attributi devono essere racchiusi da un paio di parentesi tonde (costruttore di tupla)
• La query precedente può essere espressa così:
select *
from Persona P
where (Nome,Cognome) in
(select Nome, Cognome
from Persona P1
where P1.CodFisc <> P.CodFisc)
Commenti sulle query nidificate
• L’uso di query nidificate può produrre query ‘meno dichiarative’, ma spesso si migliora la leggibilità
• Le sottointerrogazioni non possono contenere operatori insiemistici (“l’unione si fa solo al livello esterno”); la limitazione non è significativa, ed è superata da alcuni sistemi.

Commenti sulle query nidificate

• Query complesse, che fanno uso di variabili, possono diventare molto difficili da comprendere
• L’uso delle variabili deve rispettare le regole di visibilità
– una variabile può essere usata solamente all’interno della query dove viene definita o all’interno di una query che è ricorsivamente nidificata nella query dove è definita.
– se un nome di variabile è ambiguo, si assume il riferimento alla variabile più vicina.
Visibilità delle variabili
• Query scorretta:
select *
from Cliente
where CodCli in
(select CodCli
from Ordine O1
where CodOrd = ’AZ1020’)
or CodCli in
(select CodCli
from Ordine O2
where O2.Data = O1.Data)
• La query è scorretta poiché la variabile O1 non è visibile nella seconda query nidificata.

Uso di in nelle modifiche
• Aumentare di 5 euro l’importo di tutti gli ordini che comprendono il prodotto 456
update Ordine
set Importo = Importo + 5
where CodOrd in
select CodOrd
from Dettaglio
where CodProd = ’456’

Uso di query nidificate nelle modifiche
• Assegnare a TotPezzi la somma delle quantità delle linee di un ordine
update Ordine O
set TotPezzi =
(select sum(Qta)
from Dettaglio D
where D.CodOrd = O.CodOrd)