Sei sulla pagina 1di 66

SQL – Structured Query Language

SQL: caratteristiche generali

9 SQL (Structured Query Language) è il


linguaggio standard per DBMS relazionali, che
riunisce in sé funzionalità di DDL, DML e DCL
9 SQL è un linguaggio dichiarativo (non
procedurale), ovvero specifica il risultato
desiderato e non la sequenza di operazioni da
compiere per ottenere il risultato stesso
9 SQL è “relazionalmente completo”, nel senso
che ogni espressione dell’algebra relazionale
può essere tradotta in SQL
9 SQL adotta la logica a 3 valori introdotta con
l’Algebra Relazionale
SQL: standard e dialetti

9 Il processo di standardizzazione di SQL è iniziato nel


1986
9 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.
9 Del 1999 è lo standard SQL:1999, che rende SQL un
linguaggio computazionalmente completo (e quindi con
istruzioni di controllo) per il supporto di oggetti
persistenti.
9 Allo stato attuale ogni sistema ha ancora un suo dialetto:
• supporta (in larga parte) SQL-2
• ha già elementi di SQL:1999
• ha anche costrutti non standard
Data Definition Language (DDL)

9 Il DDL di SQL permette di definire schemi di


relazioni (tabelle), modificarli ed eliminarli
9 Permette di inoltre di specificare vincoli, sia a
livello di tupla (o “riga”) che a livello di tabella
9 Permette di definire nuovi domini, oltre a quelli
predefiniti
9 Inoltre si possono definire viste (“view”),
ovvero tabelle virtuali, e indici, per accedere
efficientemente ai dati
Creazione ed eliminazione di tabelle

9 Mediante l’istruzione CREATE TABLE si definisce


lo schema di una tabella e se ne crea un’istanza
vuota
9 Per ogni attributo va specificato il dominio, un
eventuale valore di default ed eventuali vincoli
9 Infine possono essere espressi altri vincoli a
livello di tupla e di tabella
9 Mediante l’istruzione DROP TABLE è possibile
eliminare lo schema di una tabella (e
conseguentemente la corrispondente istanza)
• DROP TABLE Imp
CREATE TABLE: sintassi

CREATE TABLE NomeTabella


(
NomeAttributo Dominio [ValoreDiDefault][Vincoli]
{,NomeAttributo Dominio [ValoreDiDefault][Vincoli]}
AltriVincoli
)
Creazione di tabelle: esempio

CREATE TABLE Imp (


CodImp char(4) PRIMARY KEY,
CF char(16) NOT NULL UNIQUE,
Cognome varchar(60) NOT NULL,
Nome varchar(30) NOT NULL,
Sede char(3) REFERENCES Sedi(Sede),
Ruolo varchar(20) DEFAULT ‘Programmatore’,
Stipendio int CHECK (Stipendio > 0),
UNIQUE (Cognome, Nome)
)

CREATE TABLE Prog (


CodProg char(3),
Citta varchar(40),
PRIMARY KEY (CodProg,Citta)
)
Valori nulli e valori di default

9 Per vietare la presenza di valori nulli, è


sufficiente imporre il vincolo NOT NULL
• CF char(16) NOT NULL
9 Per ogni attributo è inoltre possibile specificare
un valore di default, che verrà usato se all’atto
dell’inserimento di una tupla non viene fornito
esplicitamente un valore per l’attributo
• Ruolo varchar(20) DEFAULT ‘Programmatore’
Chiavi

9 La definizione di una chiave avviene


esprimendo un vincolo UNIQUE, che si può
specificare in linea, nella dichiarazione di un
attributo, se la chiave consiste di un singolo
attributo
• CF char(16) UNIQUE
9 o dopo aver dichiarato tutti gli attributi, se la
chiave consiste di uno o più attributi:
• UNIQUE(Cognome,Nome)
9 Ovviamente, specificare
• UNIQUE(Cognome),
UNIQUE(Nome)
9 non sarebbe equivalente, bensì molto più
restrittivo
Chiavi primarie

9 La definizione della chiave primaria di una


tabella avviene specificando un vincolo PRIMARY
KEY, o in linea o come vincolo di tupla
• CodImp char(4) PRIMARY KEY
• PRIMARY KEY (CodProg,Citta)
9 Va osservato che:
• 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
Chiavi esterne (“foreign key”)
9 La definizione di una foreign key avviene
specificando un vincolo FOREIGN KEY, e
indicando quale chiave viene referenziata
• Sede char(3) REFERENCES Sedi(Sede)
9 oppure
• FOREIGN KEY (Sede) REFERENCES Sedi(Sede)
9 Nell’esempio, Imp è detta tabella di riferimento
e Sedi tabella di destinazione (analoga
terminologia per gli attributi coinvolti)
9 Le colonne di destinazione devono essere una
chiave della tabella destinazione (non
necessariamente la chiave primaria)
9 Se si omettono gli attributi destinazione,
vengono assunti quelli della chiave primaria
• Sede char(3) REFERENCES Sedi
Vincoli generici (“check constraint”)

9 Mediante la clausola CHECK è possibile


esprimere vincoli di tupla arbitrari, sfruttando
tutto il potere espressivo di SQL
9 La sintassi è: CHECK (<condizione>)
9 Il vincolo è violato se la <condizione> è
faslsa. Pertanto
• Stipendio int CHECK (Stipendio > 0),
non permette tuple con stipendio negativo, ma
ammette valori nulli per l’attributo Stipendio
9 Se CHECK viene espresso a livello di tupla
(anziché nella definizione dell’attributo) è
possibile fare riferimento a più attributi della
tabella stessa
• CHECK (ImportoLordo = Netto + Ritenute)
Vincoli con nome

9 A fini diagnostici (e di documentazione) è


spesso utile sapere quale vincolo è stato violato
a seguito di un’azione sul DB
9 A tale scopo è possibile associare dei nomi ai
vincoli, ad esempio:
• Stipendio int CONSTRAINT StipendioPositivo
CHECK (Stipendio > 0)
9 oppure
• CONSTRAINT ForeignKeySedi FOREIGN KEY (Sede)
REFERENCES Sedi
Modifica di tabelle

9 Mediante l’istruzione ALTER TABLE è possibile modificare lo


schema di una tabella, in particolare:
• Aggiungendo attributi
• Aggiungendo o rimuovendo vincoli
9 Esempio
• ALTER TABLE Imp
ADD COLUMN Sesso char(1) CHECK (Sesso in (‘M’,‘F’))
ADD CONSTRAINT StipendioMax CHECK (Stipendio < 4000)
DROP CONSTRAINT StipendioPositivo
DROP UNIQUE(Cognome,Nome);
9 Se si aggiunge un attributo con vincolo NOT NULL, bisogna
prevedere un valore di default, che il sistema assegnerà
automaticamente a tutte le tuple già presenti
• ADD COLUMN Istruzione varchar(10) NOT NULL DEFAULT
‘Laurea’
ALTER TABLE: sintassi

ALTER TABLE NomeTabella


<
ALTER COLUMN NomeAttributo
<SET DEFAULT NuovoDefault | DROP DEFAULT > |
ADD CONSTRAINT DefVincolo |
DROP CONSTRAINT NomeVincolo |
ADD COLUMN DefAttributo |
DROP COLUMN NomeAttributo
>
Data Manipulation Language (DML)

9 Le istruzioni principali del DML di SQL sono


• SELECT esegue interrogazioni (query) sul DB
• INSERT inserisce nuove tuple nel DB
• DELETE cancella tuple dal DB
• UPDATE modifica tuple del DB
9 INSERT può usare il risultato di una query per
eseguire inserimenti multipli
9 DELETE e UPDATE possono fare uso di condizioni
per specificare le tuple da cancellare o
modificare
DB di riferimento per gli esempi
L’istruzione SELECT

9 È l’istruzione che permette di eseguire


interrogazioni (query) sul DB
9 La forma di base è:
• SELECT Attributo {,Attributo}
FROM Tabella {,Tabella}
WHERE Condizione
9 ovvero:
• TARGET list (cosa includere nel risultato)
• clausola FROM (da dove ricavare il risultato)
• clausola WHERE (la condizione da soddisfare)
SELECT su singola tabella

9 Trovare Codice, nome e ruolo


dei dipendenti della sede S01
• SELECT CodImp, Nome, Ruolo
FROM Imp
WHERE Sede = ‘S01’

9 Si ottiene in questo modo:


• La clausola FROM indica di considerare la tabella Imp
• La clausola WHERE dice di considerare solo le tuple per cui
Sede = ‘S01’
• Infine, si estraggono i valori degli attributi (o “colonne”)
nella TARGET list
9 Equivale a πCodImp,Nome,Ruolo(σSede = ‘S01’(Imp))
SELECT senza proiezione o senza condizione
9 Se si vogliono tutti gli attributi:
• SELECT CodImp, Nome, Sede, Ruolo, Stipendio
FROM Imp
WHERE Sede = ‘S01’
9 si può abbreviare con:
• SELECT *
FROM Imp
WHERE Sede = ‘S01’
9 Se si vogliono tutte le tuple si può scrivere:
• SELECT CodImp, Nome, Ruolo
FROM Imp
9 Quindi
• SELECT *
FROM Imp
restituisce tutta l’istanza di Imp
Righe duplicate: Tabelle vs Relazioni

9 Il risultato di una query SQL può


contenere righe duplicate:
• SELECT Ruolo
FROM Imp
WHERE Sede = ‘S01’
9 Per eliminarle si usa l’opzione
DISTINCT nella TARGET list
• SELECT DISTINCT Ruolo
FROM Imp
WHERE Sede = ‘S01’
Espressioni nella clausola SELECT

9 La TARGET list può contenere non solo attributi, ma


anche espressioni:
• SELECT CodImp, Stipendio*12
FROM Imp
WHERE Sede = ‘S01’
9 Si noti che in questo caso la seconda colonna non ha un
nome
Ridenominazione delle colonne

9 Ad ogni elemento della TARGET list è possibile associare


un nome:
• SELECT CodImp AS Codice, Stipendio*12 AS
StipendioAnnuo
FROM Imp
WHERE Sede = ‘S01’
9 La parola chiave AS può anche essere omessa:
• SELECT CodImp Codice,...
Pseudonimi

9 Per chiarezza, ogni nome di colonna può essere


scritto prefissandolo con il nome della tabella:
• SELECT Imp.CodImp AS Codice, Imp.Stipendio*12
AS StipendioAnnuo
FROM Imp
WHERE Imp.Sede = ‘S01’
9 …e si può anche usare uno pseudonimo (alias)
in luogo del nome della tabella
• SELECT I.CodImp AS Codice, I.Stipendio*12 AS
StipendioAnnuo
FROM Imp I -- oppure Imp AS I
WHERE I.Sede = ‘S01’
Operatore LIKE

9 L’operatore LIKE, mediante i caratteri jolly _


(un carattere arbitrario) e % (una stringa
arbitraria), permette di esprimere dei “pattern”
su stringhe
9 Trovare i Nomi degli impiegati che finiscono con
una ‘i’ e hanno una ‘i’ in seconda posizione
• SELECT Nome
FROM Imp
WHERE Nome LIKE ‘_i%i’
Operatore IN

9 L’operatore IN permette di esprimere condizioni di


appartenenza a un insieme
9 Trovare Codici e sedi degli impiegati delle sedi S02 e S03
• SELECT CodImp, Sede
FROM Imp
WHERE Sede IN (‘S02’,‘S03’)
9 Lo stesso risultato si ottiene scrivendo:
• SELECT CodImp, Sede
FROM Imp
WHERE Sede = ‘S02’ OR Sede = ‘S03’
Operatore BETWEEN

9 L’operatore BETWEEN permette di esprimere


condizioni di appartenenza a un intervallo
9 Trovare Nome e stipendio degli impiegati che
hanno uno stipendio compreso tra 1300 e 2000
Euro (estremi inclusi)
• SELECT Nome, Stipendio
FROM Imp
WHERE Stipendio BETWEEN 1300 AND 2000
Valori nulli

9 Il trattamento dei valori nulli


si basa su quanto visto in
algebra relazionale, quindi
• SELECT CodImp
FROM Imp
WHERE Stipendio > 1500
OR Stipendio <= 1500
restituisce solo
Logica a 3 valori in SQL

9 Nel caso di espressioni complesse,


SQL ricorre alla logica a 3 valori:
vero (V), falso (F) e “sconosciuto”
(?)
• SELECT CodImp, Sede, Stipendio
FROM Imp
WHERE (Sede = ‘S03’) OR
(Stipendio > 1500)

9 Per verificare se un valore è NULL si usa


l’operatore IS
• NOT (A IS NULL) si scrive anche A IS NOT NULL
9 Esempio
• SELECT CodImp
FROM Imp
WHERE Stipendio IS NULL
Ordinamento del risultato

9 Per ordinare il risultato di una


query secondo i valori di una o
più colonne si introduce la
clausola ORDER BY, e per ogni
colonna si specifica se
l’ordinamento è per valori
“ascendenti” (ASC, il default) o
“discendenti” (DESC)
• SELECT Nome, Stipendio
FROM Imp
ORDER BY Stipendio DESC, Nome
Interrogazioni su più tabelle

9 L’interrogazione
• SELECT I.Nome, I.Sede, S.Citta
FROM Imp I, Sedi S
WHERE I.Sede = S.Sede AND I.Ruolo =
‘Programmatore’
si interpreta come segue:
• Si esegue il prodotto cartesiano di Imp e Sedi
• Si applicano i predicati della clausola WHERE
• Si estraggono le colonne della TARGET list
9 Il predicato I.Sede = S.Sede è detto predicato
di join, in quanto stabilisce il criterio con cui le
tuple di Imp e di Sedi devono essere combinate
Interrogazioni su più tabelle: risultato

9 Dopo avere applicato il predicato I.Sede = S.Sede si


ottiene:
Ridenominazione del risultato

9 Se la SELECT list contiene 2 o più colonne con lo stesso


nome, è necessario operare una ridenominazione
• SELECT I.Sede AS SedeE001, S.Sede AS AltraSede
FROM Imp I, Sedi S
WHERE I.Sede <> S.Sede AND I.CodImp = ‘E001’
Self Join

9 L’uso di alias è forzato quando si deve eseguire un self-


join
9 Trovare i nonni di Anna
• SELECT G1.Genitore AS Nonno
FROM Genitori G1, Genitori G2
WHERE G1.Figlio = G2.Genitore AND G2.Figlio =
‘Anna’
Join espliciti

9 Anziché scrivere i predicati di join nella clausola


WHERE, è possibile “costruire” una joined table
direttamente nella clausola FROM
• SELECT I.Nome, I.Sede, S.Citta
FROM Imp I JOIN Sedi S ON (I.Sede = S.Sede)
WHERE I.Ruolo = ‘Programmatore’
in cui JOIN si può anche scrivere INNER JOIN
9 Altri tipi di join espliciti sono:
• LEFT [OUTER] JOIN
• RIGHT [OUTER] JOIN
• FULL [OUTER] JOIN
• NATURAL JOIN
Operatori insiemistici

9 L’istruzione SELECT non permette di eseguire unione,


intersezione e differenza di tabelle
9 Ciò che si può fare è combinare in modo opportuno i
risultati di due istruzioni SELECT, mediante gli operatori
• UNION, INTERSECT, EXCEPT
9 In tutti i casi gli elementi delle TARGET list devono avere
tipi compatibili e gli stessi nomi se si vogliono colonne
con un’intestazione definita
9 L’ordine degli elementi è importante (notazione
posizionale)
9 Il risultato è in ogni caso privo di duplicati; per
mantenerli occorre aggiungere l’opzione ALL:
• UNION ALL, INTERSECT ALL, EXCEPT ALL
Operatori insiemistici: esempi (1/2)
Operatori insiemistici: esempi (2/2)
Istruzioni di aggiornamento dei dati

9 Le istruzioni che permettono di aggiornare il DB


sono
• INSERT inserisce nuove tuple nel DB
• DELETE cancella tuple dal DB
• UPDATE modifica tuple del DB
9 INSERT può usare il risultato di una query per
eseguire inserimenti multipli
9 DELETE e UPDATE possono fare uso di condizioni
per specificare le tuple da cancellare o
modificare
9 In ogni caso gli aggiornamenti riguardano una
sola relazione
Inserimento di tuple: caso singolo

9 È possibile inserire una nuova tupla


specificandone i valori
• INSERT INTO Sedi(Sede,Responsabile,Citta)
VALUES (‘S04’,‘Bruni’,‘Firenze’)
9 Ci deve essere corrispondenza tra attributi e
valori
9 La lista degli attributi si può omettere, nel qual
caso vale l’ordine con cui sono stati definiti
9 Se la lista non include tutti gli attributi, i
restanti assumono valore NULL (se ammesso) o
il valore di default (se specificato)
• INSERT INTO Sedi(Sede,Citta) VALUES
(‘S04’,‘Firenze’)
Inserimento di tuple: caso multiplo

9 È possibile anche inserire le tuple che risultano


da una query
• INSERT INTO SediBologna(SedeBO,Resp)
SELECT Sede,Responsabile
FROM Sedi
WHERE Citta = ‘Bologna’
9 Valgono ancora le regole viste per il caso
singolo
9 Gli schemi del risultato e della tabella in cui si
inseriscono le tuple possono essere diversi,
l’importante è che i tipi delle colonne siano
compatibili
Cancellazione di tuple

9 L’istruzione DELETE può fare uso di una


condizione per specificare le tuple da
cancellare. L’istruzione
• DELETE FROM Sedi WHERE Citta = ‘Bologna’
elimina le sedi di Bologna
9 Che succede se la cancellazione porta a violare
il vincolo di integrità referenziale?
• Ad es.: che accade agli impiegati delle sedi di
Bologna?
• Dipende dalle politiche di “reazione”
Modifica di tuple

9 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’, Citta = ‘Firenze’
WHERE Sede = ‘S01’
• UPDATE Imp
SET Stipendio = 1.1*Stipendio
WHERE Ruolo = ‘Programmatore’
9 Anche l’UPDATE può portare a violare il vincolo
di integrità referenziale
Politiche di “reazione”

9 Anziché lasciare al programmatore il compito di garantire


che a fronte di cancellazioni e modifiche i vincoli di
integrità referenziale siano rispettati, si possono
specificare opportune politiche di reazione in fase di
definizione degli schemi
• CREATE TABLE Imp (
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
)
9 Altre politiche: SET NULL e SET DEFAULT
Informazioni di sintesi

9 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’, ecc.
9 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.
9 A tale scopo SQL mette a disposizione due strumenti di
base:
• Funzioni aggregate
• Clausola GROUP BY
DB di riferimento per gli esempi
Funzioni aggregate (1/2)

9 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 conteggio
9 Esempio: trovare il totale degli stipendi della
sede ‘S01’
• SELECT SUM(Stipendio) AS ToTStipS01
FROM Imp
WHERE Sede = ‘S01’
Funzioni aggregate (2/2)

9 L’argomento di una funzione aggregata è una


qualunque espressione che può figurare nella
TARGET list (ma non un’altra funzione aggregata!)
• SELECT SUM(Stipendio*12) AS ToTStipAnnuiS01
FROM Imp
WHERE Sede = ‘S01’
9 Tutte le funzioni, ad eccezione di COUNT, ignorano i
valori nulli
9 Il risultato è NULL se tutti i valori sono NULL
9 L’opzione DISTINCT considera solo i valori distinti
• SELECT SUM(DISTINCT Stipendio)
FROM Imp
WHERE Sede = ‘S01’
COUNT e valori nulli

9 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


FROM Imp
WHERE Sede = ‘S01’

• SELECT COUNT(Stipendio) AS
NumStipS01
FROM Imp
WHERE Sede = ‘S01’
Funzioni aggregate e tipo del risultato

9 Per alcune funzioni aggregate, al fine


di ottenere il risultato desiderato, è
necessario operare un casting
dell’argomento

• SELECT AVG(Stipendio) AS AvgStip


FROM Imp

• SELECT AVG(CAST(Stipendio AS
Decimal(6,2))) AS AvgStip
FROM Imp
Clausola SELECT e funzioni aggregate

9 Se si usano funzioni aggregate, la TARGET list non può


includere altri elementi che non siano a loro volta
funzioni aggregate. Ad esempio
• SELECT Nome, MIN(Stipendio)
FROM Imp
non è corretta, viceversa
• SELECT MIN(Stipendio), MAX(Stipendio)..
è corretta
9 Il motivo è che una funzione aggregata restituisce un
singolo valore, mentre il riferimento a una colonna è in
generale un insieme di valori (eventualmente ripetuti)
9 Nel caso specifico (chi sono gli impiegati con stipendio
minimo?) è necessario ricorrere a un’altra soluzione, che
vedremo più avanti
Funzioni aggregate e raggruppamento

9 I valori di sintesi calcolati dalle funzioni aggregate si


riferiscono a tutte le tuple che soddisfano le condizioni
delle clausola WHERE
9 In molti casi è viceversa opportuno fornire tali valori per
gruppi omogenei di tuple (es: impiegati di una stessa
sede)
9 La clausola GROUP BY serve a definire tali gruppi,
specificando una o più colonne (di raggruppamento) sulla
base della/e quale/i le tuple sono raggruppate per valori
uguali
• SELECT Sede, COUNT(*) AS NumProg
FROM Imp
WHERE Ruolo = ‘Programmatore’
GROUP BY Sede
9 La TARGET list può includere le colonne di
raggruppamento, ma non altre!
Come si ragiona con il GROUP BY

9 Le tuple che soddisfano la


clausola WHERE…

9 …sono raggruppate per


valori uguali della/e
colonna/e presenti nella
clausola GROUP BY…

9 …e infine a ciascun
gruppo si applica la
funzione aggregata
GROUP BY: esempi

1. Per ogni ruolo, lo stipendio medio nelle sedi di


Milano
9 SELECT I.Ruolo, AVG(I.Stipendio) AS AvgStip
FROM Imp I JOIN Sedi S ON (I.Sede = S.Sede)
WHERE S.Citta = ‘Milano’
GROUP BY I.Ruolo

2. Per ogni sede di Milano, lo stipendio medio


9 SELECT I.Sede, AVG(I.Stipendio) AS AvgStip
FROM Imp I JOIN Sedi S ON (I.Sede = S.Sede)
WHERE S.Citta = ‘Milano’
GROUP BY I.Sede

3. Per ogni ruolo e sede di Milano, lo stipendio


medio
9 SELECT I.Sede, I.Ruolo, AVG(I.Stipendio)
FROM Imp I JOIN Sedi S ON (I.Sede = S.Sede)
WHERE S.Citta = ‘Milano’
GROUP BY I.Sede, I.Ruolo
Raggruppamento e proiezione

9 Quando la TARGET list include solo le colonne


di raggruppamento, il tutto è equivalente a ciò
che si otterrebbe omettendo il GROUP BY e
rimuovendo i duplicati con l’opzione DISTINCT
• SELECT Sede
FROM Imp
GROUP BY Sede
9 equivale pertanto a
• SELECT DISTINCT Sede
FROM Imp
Condizioni sui gruppi

9 Oltre a poter formare dei gruppi, è


anche possibile selezionare dei
gruppi sulla base di loro proprietà
“complessive”
• SELECT Sede, COUNT(*) AS NumImp
FROM Imp
GROUP BY Sede
HAVING COUNT(*) > 2
9 La clausola HAVING ha per i gruppi
una funzione simile a quella che la
clausola WHERE ha per le tuple
(attenzione a non confonderle!)
Tipi di condizioni sui gruppi

9 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
• SELECT Sede, COUNT(*) AS NumImp
FROM Imp
GROUP BY Sede
HAVING Sede <> ‘S01’
equivale a
• SELECT Sede, COUNT(*) AS NumImp
FROM Imp
WHERE Sede <> ‘S01’
GROUP BY Sede
Un esempio completo

9 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
• SELECT I.Sede, AVG(Stipendio) AS AvgStipendio
FROM Imp I, Sedi S
WHERE I.Sede = S.Sede AND S.Citta = ‘Bologna’
GROUP BY I.Sede
HAVING COUNT(*) >= 3
ORDER BY AvgStipendio DESC, Sede
9 L’ordine delle clausole è sempre come nell’esempio
9 Si ricordi che il GROUP BY non implica alcun
ordinamento del risultato
Subquery

9 Oltre alla forma “flat” vista sinora, in SQL è


anche possibile esprimere delle condizioni che
si basano sul risultato di altre interrogazioni
(subquery o query innestate o query nidificate)
• SELECT CodImp -- impiegati delle sedi di Milano
FROM Imp
WHERE Sede IN (SELECT Sede
FROM Sedi
WHERE Citta = ‘Milano’)
9 La subquery restituisce l’insieme di sedi
(‘S01’,’S03’), e quindi il predicato nella clausola
WHERE esterna equivale a
• WHERE Sede IN (‘S01’,‘S03’)
Subquery scalari

9 Gli operatori di confronto =, <,… si possono usare solo


se la subquery restituisce non più di una tupla
(subquery “scalare”)
• SELECT CodImp -- impiegati con stipendio minimo
FROM Imp
WHERE Stipendio = (SELECT MIN(Stipendio)
FROM Imp)
9 La presenza di vincoli può essere sfruttata a tale
scopo
• SELECT Responsabile
FROM Sedi
WHERE Sede = (SELECT Sede -- al massimo una sede
FROM Imp
WHERE CodImp = ‘E001’)
Subquery: caso generale

9 Se la subquery può restituire più di un valore si devono


usare le forme
• <op> ANY: la relazione <op> deve valere per almeno uno dei
valori
• <op> ALL : la relazione <op> deve valere per tutti i valori
9 Esempi
• SELECT Responsabile
FROM Sedi
WHERE Sede = ANY (SELECT Sede
FROM Imp
WHERE Stipendio > 1500)
• SELECT CodImp -- impiegati con stipendio minimo
FROM Imp
WHERE Stipendio <= ALL (SELECT Stipendio
FROM Imp)
9 La forma = ANY equivale a IN
Subquery: livelli multipli di innestamento

9 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 Imp
WHERE Sede IN (SELECT Sede
FROM Sedi
WHERE Citta NOT IN (SELECT Citta
FROM Prog
WHERE CodProg = ‘P02’))
9 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.Citta <> Prog.Citta
AND Prog.CodProg = ‘P02’)
Subquery: quantificatore esistenziale

9 Mediante EXISTS (SELECT * …) è possibile verificare se


il risultato di una subquery restituisce almeno una tupla
• SELECT Sede
FROM Sedi S
WHERE EXISTS (SELECT *
FROM Imp
WHERE Ruolo = ‘Programmatore’)
9 Facendo uso di NOT EXISTS il predicato è vero se la
subquery non restituisce alcuna tupla
9 In entrambi i casi la cosa non è molto “interessante” in
quanto il risultato della subquery è sempre lo stesso,
ovvero non dipende dalla specifica tupla del blocco
esterno
Subquery correlate

9 Se la subquery fa riferimento a “variabili” definite in un


blocco esterno, allora si dice che è correlata
• SELECT Sede -- sedi con almeno un programmatore
FROM Sedi S
WHERE EXISTS (SELECT *
FROM Imp
WHERE Ruolo = ‘Programmatore’
AND Sede = S.Sede)
9 Adesso il risultato della query innestata dipende dalla
sede specifica, e la semantica quindi diventa:
• Per ogni tupla del blocco esterno, considera il valore di
S.Sede e risolvi la query innestata
Subquery: “unnesting” (1/2)

9 È spesso possibile ricondursi a una forma “piatta”, ma la


cosa non è sempre così ovvia. Ad esempio, nell’esempio
precedente si può anche scrivere
• SELECT DISTINCT Sede
FROM Sedi S, Imp I
WHERE S.Sede = I.Sede AND I.Ruolo = ‘Programmatore’
9 Si noti la presenza del DISTINCT
9 La forma innestata è “più procedurale” di quella piatta e,
a seconda dei casi, può risultare più semplice da derivare
9 Si ricordi comunque che in una subquery non si possono
usare operatori insiemistici (UNION, INTERSECT e EXCEPT)
e che una subquery può comparire solo come operando
destro in un predicato
Subquery: “unnesting” (2/2)

9 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,
ma nella forma piatta:
• SELECT DISTINCT Sede
FROM Sedi S LEFT OUTER JOIN Imp I ON (S.Sede =
I.Sede) AND (I.Ruolo = ‘Programmatore’)
WHERE I.CodImp IS NULL
9 È facile sbagliare, ad esempio la seguente query non è
corretta
• SELECT DISTINCT Sede
FROM Sedi S LEFT OUTER JOIN Imp I ON (S.Sede =
I.Sede)
WHERE I.Ruolo = ‘Programmatore’ AND I.CodImp IS
NULL
9 perché la clausola WHERE non è mai soddisfatta!