Sei sulla pagina 1di 7

Mini dispensa SQL

Sommario
Schema di riferimento ....................................................................................................................................... 1
IN/NOT IN .......................................................................................................................................................... 2
ANY|ALL ............................................................................................................................................................. 3
EXISTS/NOT EXISTS ............................................................................................................................................ 4
GROUP BY, HAVING, WHERE ............................................................................................................................. 5
Viste ................................................................................................................................................................... 6

Schema di riferimento
CICLISTA (nomeciclista, nazionalità)

GARA (nomegara, anno, partenza, lunghezza)

CLASSIFICA (nomegara, anno, nomeciclista, posizione)


FK nomegara REFERENCES gara
FK nomeciclista REFERENCES ciclista

La posizione è uguale a R se il ciclista è ritirato

1
IN/NOT IN
Sintassi:

SELECT *
FROM TBL
WHERE TBL.FIELD IN | NOT IN (
SUBQUERY
)

Si utilizza per verificare se un valore è contenuto (IN) o meno (NOT IN) tra i risultati della subquery. Il costrutto
IN restituisce TRUE se il valore è contenuto tra quelli ritornati dalla subquery, il NOT IN se non è contenuto.

Il NOT IN si utilizza quando si esegue una differenza. Il costrutto IN spesso può essere sostituito con un JOIN,
mentre il NOT IN no!

Esempio
Selezionare i ciclisti che si sono ritirati almeno una volta ad una gara
Questa query può essere espressa sia con un JOIN:

SELECT DISTINCT C.*


FROM CICLISTA C
JOIN CLASSIFICA CL ON CL.nomeciclista = C.nomeciclista
WHERE posizione = ‘R’

Sia con un IN:

SELECT *
FROM CICLISTA
WHERE nomeciclista IN (
SELECT nomeciclista
FROM CLASSIFICA
WHERE posizione = ‘R’
)

In entrambe le query si va a selezionare i ciclisti che si sono ritirati ad almeno una gara, l’unica differenza tra
le due è che la prima esclude naturalmente i duplicati, in quanto la verifica viene fatta per ogni ciclista, mentre
la seconda valuta la condizione dopo il JOIN, quindi un ciclista comparirà tante volte quante volte sono le
gare in cui si è ritirato.
Per eliminare i duplicati si può utilizzare il costrutto SELECT DISTINCT.

Le query con il NOT IN, ossia le sottrazioni, non possono essere risolte con il JOIN.

Esempio
selezionare i ciclisti che non si sono mai ritirati da una gara

Questa soluzione è ERRATA:

SELECT DISTINCT C.*


FROM CICLISTA C
JOIN CLASSIFICA CL ON CL.nomeciclista = C.nomeciclista
WHERE posizione <> ‘R’

Perché si va ad escludere solamente i record che hanno il valore della posizione uguale ad ‘R’, e quindi se il
ciclista ha partecipato ad altre gare ed ha raggiunto l’arrivo, comparirà tra i risultati.
2
Una soluzione CORRETTA è la seguente:

SELECT *
FROM CICLISTA
WHERE nomeciclista NOT IN (
SELECT nomeciclista
FROM CLASSIFICA
WHERE posizione = ‘R’
)

In questo caso ogni ciclista viene valutato sul set dei valori dei ritirati, e quindi viene escluso se si è ritirato
anche solo una volta.

ANY|ALL
Sintassi:

SELECT *
FROM TBL
WHERE TBL.FIELD > ALL|ANY(
SUBQUERY
)

ALL ed ANY consentono di confrontare un valore con un set di valori restituito da una subquery, possono
essere usati con >=, <=, >, <.

L’operatore ANY ritorna true se almeno uno dei valori restituiti dalla subquery soddisfa la condizione imposta,
ALL ritorna true se tutti i valori ritornati dalla subquery soddisfano la condizione imposta.

Attenzione a confrontare sempre cose comparabili! La subquery all’interno deve sempre ritornare un solo
campo!

Esempio
selezionare la gara con la lunghezza maggiore

SELECT *
FROM GARA
WHERE lunghezza >= ALL (
SELECT lunghezza
FROM GARA
)

In questo caso ogni lunghezza di ogni gara viene confrontata con tutte le altre, e vengono mantenute solo
le gare con lunghezza maggiore/uguale a tutte le altre (ossia quelle più lunghe).

3
EXISTS/NOT EXISTS
Sintassi

SELECT *
FROM TBL
WHERE EXISTS|NOT EXISTS(
SUBQUERY
)

Questo costrutto serve per valutare una condizione tramite una subquery. Con EXISTS se la subquery non
ritorna risultati il record esterno viene scartato, invece se ritorna qualcosa viene mantenuto, la logica con il
NOT è la stessa ma negata. La subquery va SEMPRE legata alla query esterna imponendo una condizione
nella WHERE che le lega. Non è importante che cosa si seleziona nella SELECT, in quanto viene valutato solo
se ci sono o meno risultati, non il valore degli stessi. Inoltre non serve a confrontare valori, quindi non va
specificato nessun attributo di riferimento nella WHERE.

Esempio

Le query di prima possono essere riscritte con EXISTS/NOT EXISTS.

Selezionare i ciclisti che si sono ritirati almeno una volta ad una gara può essere riscritta come selezionare i
ciclisti per cui esiste una gara in cui si sono ritirati:

SELECT *
FROM CICLISTA AS C
WHERE EXISTS (
SELECT *
FROM CLASSIFICA AS CL
WHERE CL.nomeciclista = C.nomeciclista
AND posizione = ‘R’

Come si può notare la query interna è stata legata a quella esterna, e quindi per ogni ciclista viene verificato
se esistono gare in cui si è ritirato, se ne esistono (la subquery ritorna qualcosa) viene mantenuto, altrimenti
viene eliminato. Notare anche che la EXISTS non è associata a nessun attributo, non serve a comparare dei
valori!

Anche l’altra query può essere riscritta con un NOT EXISTS: selezionare i ciclisti che non si sono mai ritirati da
una gara, può essere riscritta come selezionare i ciclisti per cui NON ESISTE una gara in cui si sono ritirati:

SELECT *
FROM CICLISTA AS C
WHERE NOT EXISTS (
SELECT *
FROM CLASSIFICA AS CL
WHERE CL.nomeciclista = C.nomeciclista
AND posizione = ‘R’

4
GROUP BY, HAVING, WHERE
Sintassi:
SELECT field1, field2, …
FROM TBL
WHERE conditions
GROUP BY field1, field2, …
HAVING conditions

GROUP BY serve a raggruppare i risultati in base a uno o più campi. All’interno della SELECT possono essere
inseriti dei campi che appartengono alle tabelle contenute nella FROM, oppure delle funzioni per calcolare
dei valori aggregati. Funzioni tipiche sono:

• COUNT: conta il numero di valori, si possono avere diverse varianti:


o COUNT(*) – conta il numero di record;
o COUNT(FIELD) – conta il numero di valori assunti dal campo FIELD, i valori NON SONO
DISTINTI, quindi se un valore compare più volte sarà contato più volte;
o COUNT(DISTINCT FIELD) – conta il numero di valori distinti assunti dal campo FIELD, quindi
se un valore compare più volte lo conterà una volta sola.
• SUM(FIELD): esegue la somma dei valori assunti dal campo FIELD, che deve per forza di cose essere
numerico.
• MAX(FIELD): mantiene il valore massimo assunto da FIELD.
• MIN(FIELD): mantiene il valore minimo assunto da FIELD.
• AVG(FIELD): esegue la media dei valori assunti da FIELD.

All’interno della condizione di GROUP BY devono essere inseriti TUTTI i campi inseriti all’interno della SELECT,
eccetto quelli aggregati (quindi non si mettono le funzioni di aggregazione), inoltre è possibile inserire anche
campi in più. Quindi la condizione di GROUP BY deve contenere tutti i campi messi nella SELECT tranne le
funzioni di aggregazione, ma non vale il viceversa.

Esempio
selezionare per ogni ciclista il numero di gare a cui ha partecipato

SELECT nomeciclista, COUNT(*) AS num_gare


FROM CLASSIFICA
GROUP BY nomeciclista

La query raggruppa i record contenuti nella tabella CLASSIFICA per il ciclista, e poi va a contare con la funzione
COUNT(*) il numero di record associati ad ogni ciclista, che corrisponde al numero di gare a cui ha
partecipato.

Il costrutto WHERE consente di applicare delle condizioni sui record PRIMA che venga eseguita la GROUP BY,
mentre la funzione HAVING consente di applicare delle condizioni DOPO l’esecuzione della GROUP BY, e
quindi di lavorare sui risultati delle funzioni di aggregazione.

5
Esempio
selezionare i ciclisti italiani che hanno partecipato ad almeno 10 gare.

SELECT c.nomeciclista
FROM CICLISTA c
JOIN CLASSIFICA cl ON cl.nomeciclista = c.nomeciclista
WHERE c.nazionalità = ‘italiana’
GROUP BY c.nomeciclista
HAVING COUNT(*) >= 10

La condizione sulla nazionalità viene imposta nella WHERE, in quanto deve essere fatta prima della GROUP
BY per selezionare solo i ciclisti italiani, mentre la condizione sul numero di gare a cui hanno partecipato
viene messa nell’HAVING, in quanto viene calcolata dopo il raggruppamento con una funzione di
aggregazione (COUNT).

Anche nella HAVING è possibile usare delle subquery.

Esempio
selezionare il ciclista che ha vinto più gare di tutti

SELECT nomeciclista, COUNT(*) AS num_gare_vinte


FROM CLASSIFICA
WHERE posizione = 1
GROUP BY nomeciclista
HAVING COUNT(*) >= ALL(
SELECT COUNT(*)
FROM CLASSIFICA
WHERE posizione = 1
GROUP BY nomeciclista
);

La query esterna prende i ciclisti che sono arrivati in prima posizione (condizione nella WHERE), dopodiché
esegue il raggruppamento (GROUP BY) e conta quante gare hanno vinto (COUNT(*)), poi va ad imporre che
il conteggio sia maggiore o uguale di tutti gli altri numeri di gare vinte. Il numero di gare vinte da ogni ciclista
viene calcolato con la subquery.

Viste
Sintassi

CREATE VIEW nomevista AS


query

Una vista è una query che viene memorizzata all’interno del DB a cui viene assegnato un nome, una volta
creata può essere interrogata come se fosse una normale tabella.

Ad esempio la query “selezionare il ciclista che ha vinto più gare di tutti” può essere spezzata in due parti
usando una vista:

6
Prima si crea una vista che calcola le vittorie per ogni ciclista

CREATE VIEW vittorie_per_ciclista AS


SELECT nomeciclista, COUNT(*) AS num_gare_vinte
FROM CLASSIFICA
WHERE posizione = 1
GROUP BY nomeciclista

Poi si usa la vista per ottenere il ciclista con più vittorie

SELECT *
FROM vittorie_per_ciclista
WHERE num_gare_vinte >= ALL(
SELECT num_gare_vinte
FROM vittorie_per_ciclista
)

Potrebbero piacerti anche