Capitolo 4


Le clausole SQL

Questo capitolo è dedicato alle clausole utilizzate con l’istruzione SELECT , in particolare saranno trattate le seguenti clausole:

Negli esempi di questo capitolo, quando non verrà specificato diversamente, si utilizzerà la seguente tabella:

ASSEGNI

ASSEGNO
-------------------

BENEFICIARIO
---------------------------------------
IMPORTO
-------------------
NOTE
---------------------------------------
1 COMPUTER SHOP
50 000
DISCHETTI E CD-ROM
2 LIBRERIE CULTURA
245 000
LIBRI, CANCELLERIA
3 COMPUTER SHOP
200 000
TELEFONO CELLULARE
4 BIOGAS SRL
88 000
GAS
5 SUPERMARCHET GS
150 000
ALIMENTARI
16 ASSICURAZIONI ASSO
425 000
ASSICURAZIONE CASA
17 GAS S.P.A.
25 000
GAS
21 COMPUTER SHOP
34 000
CONTROLLER
20 ABITI BELLA
110 000
PANTALONI
9 ABITI BELLA
224 000
COMPLETO DONNA
8 COMPUTER SHOP
134 000
JOYSTICK

WHERE

La clausola WHERE serve per implementare delle condizioni verificabili a livello delle singole righe.
Questa clausola è abbastanza semplice da usare ed è già stata utilizzata precedentemente in questo corso, vediamo un esempio:

SELECT * FROM ASSEGNI
WHERE IMPORTO < 150000;

ASSEGNO
-------------------

BENEFICIARIO
---------------------------------------
IMPORTO
-------------------
NOTE
---------------------------------------
1 COMPUTER SHOP
50 000
DISCHETTI E CD-ROM
4 BIOGAS SRL
88 000
GAS
17 GAS S.P.A.
25 000
GAS
21 COMPUTER SHOP
34 000
CONTROLLER
20 ABITI BELLA
110 000
PANTALONI
8 COMPUTER SHOP
134 000
JOYSTICK

Come possiamo vedere dall’esempio la condizione ‘IMPORTO < 150000’, implementata tramite la clausola WHERE, è stata posta a tutte le righe della tabella e solo per quelle righe dove tale condizione è risultata soddisfatta che sono stati estrapolati e visualizzati i dati secondo gli argomenti dell’istruzione SELECT.

ORDER BY

A volte potrebbe essere necessario presentare i risultati di una query in un certo ordine, la clausola ORDER BY assolve a questo scopo. Vediamo alcuni esempi:

SELECT *
FROM ASSEGNI
ORDER BY BENEFICIARIO;

ASSEGNO
-------------------

BENEFICIARIO
---------------------------------------
IMPORTO
-------------------
NOTE
---------------------------------------
20 ABITI BELLA
110 000
PANTALONI
9 ABITI BELLA
224 000
COMPLETO DONNA
16 ASSICURAZIONI ASSO
425 000
ASSICURAZIONE CASA
4 BIOGAS SRL
88 000
GAS
1 COMPUTER SHOP
50 000
DISCHETTI E CD-ROM
3 COMPUTER SHOP
200 000
TELEFONO CELLULARE
8 COMPUTER SHOP
134 000
JOYSTICK
21 COMPUTER SHOP
34 000
CONTROLLER
17 GAS S.P.A.
25 000
GAS
2 LIBRERIE CULTURA
245 000
LIBRI, CANCELLERIA
5 SUPERMARCHET GS
150 000
ALIMENTARI

E’ possibile ordinare i record in senso inverso, con la lettera o il numero più alti in prima posizione? Si che è possibile, tramite la parola chiave DESC. Vediamo un esempio:

SELECT *
FROM ASSEGNI
ORDER BY BENEFICIARIO DESC;

ASSEGNO
-------------------

BENEFICIARIO
---------------------------------------
IMPORTO
-------------------
NOTE
---------------------------------------
5 SUPERMARCHET GS
150 000
ALIMENTARI
2 LIBRERIE CULTURA
245 000
LIBRI, CANCELLERIA
17 GAS S.P.A.
25 000
GAS
1 COMPUTER SHOP
50 000
DISCHETTI E CD-ROM
21 COMPUTER SHOP
34 000
CONTROLLER
3 COMPUTER SHOP
200 000
TELEFONO CELLULARE
8 COMPUTER SHOP
134 000
JOYSTICK
4 BIOGAS SRL
88 000
GAS
16 ASSICURAZIONI ASSO
425 000
ASSICURAZIONE CASA
20 ABITI BELLA
110 000
PANTALONI
9 ABITI BELLA
224 000
COMPLETO DONNA

Esiste anche la parola chiave facoltativa ASC per l’ordinamento ascendente. Comunque questa parola chiave è raramente utilizzata in quanto superflua. Infatti ORDER BY, se non viene specificato diversamente, ordina per l’appunto in modo ascendente.

La clausola ORDER BY può essere applicata a più campi. Vediamo alcuni esempi:

SELECT BENEFICIARIO, NOTE
FROM ASSEGNI
ORDER BY BENEFICIARIO, NOTE;

BENEFICIARIO
---------------------------------------
NOTE
-------------
ABITI BELLA COMPLETO DONNA
ABITI BELLA PANTALONI
ASSICURAZIONI ASSO ASSICURAZIONE CASA
BIOGAS SRL GAS
COMPUTER SHOP CONTROLLER
COMPUTER SHOP DISCHETTI E CD-ROM
COMPUTER SHOP JOYSTICK
COMPUTER SHOP TELEFONO CELLULARE
GAS S.P.A. GAS
LIBRERIE CULTURA LIBRI, CANCELLERIA
SUPERMARCHET GS ALIMENTARI

SELECT BENEFICIARIO, NOTE
FROM ASSEGNI
ORDER BY BENEFICIARIO, NOTE DESC;

BENEFICIARIO
---------------------------------------
NOTE
----------------------
ABITI BELLA PANTALONI
ABITI BELLA COMPLETO DONNA
ASSICURAZIONI ASSO ASSICURAZIONE CASA
BIOGAS SRL GAS
COMPUTER SHOP TELEFONO CELLULARE
COMPUTER SHOP JOYSTICK
COMPUTER SHOP DISCHETTI E CD-ROM
COMPUTER SHOP CONTROLLER
GAS S.P.A. GAS
LIBRERIE CULTURA LIBRI, CANCELLERIA
SUPERMARCHET GS ALIMENTARI

Possiamo far riferimento ai campi da ordinare dopo ORDER BY indicando invece del loro nome il valore dell’ordine di apparizione all’interno della tabella. Vediamo un esempio:

SELECT *
FROM ASSEGNI
ORDER BY 3;

ASSEGNO
-------------------

BENEFICIARIO
---------------------------------------
IMPORTO
-------------------
NOTE
---------------------------------------
17 GAS S.P.A.
25 000
GAS
21 COMPUTER SHOP
34 000
CONTROLLER
1 COMPUTER SHOP
50 000
DISCHETTI E CD-ROM
4 BIOGAS SRL
88 000
GAS
20 ABITI BELLA
110 000
PANTALONI
8 COMPUTER SHOP
134 000
JOYSTICK
5 SUPERMARCHET GS
150 000
ALIMENTARI
3 COMPUTER SHOP
200 000
TELEFONO CELLULARE
9 ABITI BELLA
224 000
COMPLETO DONNA
2 LIBRERIE CULTURA
245 000
LIBRI, CANCELLERIA
16 ASSICURAZIONI ASSO
425 000
ASSICURAZIONE CASA

I dati sono stati visualizzati ordinandoli per il campo IMPORTO che è appunto il terzo campo che appare nella tabella ASSEGNI.

GROUP BY

Questa clausola ci permette di formare dei sottoinsiemi per quelle colonne specificate. Vediamo cosa significa quanto affermato.

SELECT BENEFICIARIO
FROM ASSEGNI
GROUP BY BENEFICIARIO;

BENEFICIARIO
---------------------------------------
ABITI BELLA
ASSICURAZIONI ASSO
BIOGAS SRL
COMPUTER SHOP
GAS S.P.A.
LIBRERIE CULTURA
SUPERMARCHET GS

Il risultato della query è una lista di beneficiari, che appaiono però una sola volta, anche se nella tabella di origine la maggior parte di essi compare più volte.

Questa clausola è usata molto spesso per applicare le funzioni di gruppo non a tutte le righe indistintamente, maasottoinsiemidiesse.Vediamounesempio:

Vogliamosaperequantoèstatoelargito,intotale,perognibeneficiario:

SELECTBENEFICIARIO,SUM(IMPORTO)
FROMASSEGNI
GROUPBYBENEFICIARIO;

BENEFICIARIO
---------------------------------------
SUM(IMPORTO)
---------------------------
ABITIBELLA
334000
ASSICURAZIONIASSO
425000
BIOGASSRL
88000
COMPUTERSHOP
418000
GASS.P.A.
25000
LIBRERIECULTURA
245000
SUPERMARCHETGS
150000

InquestaqueryvieneapplicatalafunzionedigruppoSUMperognisottoinsiemediBENEFICIARIO.

DaquestopuntoinpoidovremoconsiderarecheallatabellaASSEGNIsonostatiaggiuntiiseguentirecord:

22
ABITIBELLA
79000
PANTALONI
23 BIOGASSRL
399000
GAS
24 LIBRERIECULTURA
224000
LIBRI,CANCELLERIA
25 COMPUTERSHOP
88000
CONTROLLER

Quindilatabellacosìmodificataapparirànelseguentemodo:

ASSEGNI

ASSEGNO
-------------------

BENEFICIARIO
---------------------------------------
IMPORTO
-------------------
NOTE
---------------------------------------
1 COMPUTERSHOP
50000
DISCHETTIECD-ROM
2 LIBRERIECULTURA
245000
LIBRI,CANCELLERIA
3 COMPUTERSHOP
200000
TELEFONOCELLULARE
4 BIOGASSRL
88000
GAS
5 SUPERMARCHETGS
150000
ALIMENTARI
16 ASSICURAZIONIASSO
425000
ASSICURAZIONECASA
17 GASS.P.A.
25000
GAS
21 COMPUTERSHOP
34000
CONTROLLER
20 ABITIBELLA
110000
PANTALONI
9 ABITIBELLA
224000
COMPLETODONNA
8 COMPUTERSHOP
134000
JOYSTICK
22
ABITIBELLA
79000
PANTALONI
23 BIOGASSRL
399000
GAS
24 LIBRERIECULTURA
224000
LIBRI,CANCELLERIA
25 COMPUTERSHOP
88000
CONTROLLER

ÈpossibileapplicarelaclausolaGROUPBYancheapiùdiuncampopervolta.Vediamocomefunziona:

SELECTBENEFICIARIO,NOTE
FROMASSEGNI
GROUPBYBENEFICIARIO,NOTE;

BENEFICIARIONOTE
------------------------------------------------------
NOTE
-----------------------
ABITIBELLA COMPLETODONNA
ABITIBELLA PANTALONI
ASSICURAZIONIASSO ASSICURAZIONECASA
BIOGASSRL GAS
COMPUTERSHOP CONTROLLER
COMPUTERSHOP DISCHETTIECD-ROM
COMPUTERSHOP JOYSTICK
COMPUTERSHOP TELEFONOCELLULARE
GASS.P.A. GAS
LIBRERIECULTURA LIBRI,CANCELLERIA
SUPERMARCHETGS ALIMENTARI

In questa query le righe selezionate sono 11 contro le 15 della tabella originale, cosa è successo?
È avvenuto che la dove il beneficiario presentava le stesse note, veniva visualizzato una volta sola.
Si veda quante volte appare, nella tabella ASSEGNI, in NOTE ‘libricancelleria’, ‘gas’ (per beneficiario Biogas SRL), ‘controller’ e ‘pantaloni’.

Vediamo altri esempi:

Vogliamo sapere oltre a quanto è stato elargito per ogni beneficiario, quante volte il singolo beneficiario compare nella tabella:

SELECT BENEFICIARIO, SUM(IMPORTO), COUNT(BENEFICIARIO)
FROM ASSEGNI
GROUP BY BENEFICIARIO;

BENEFICIARIO
-----------------------------------
SUM(IMPORTO)
--------------------------
COUNT(BENEFICIARIO)
--------------------------------------
ABITIBELLA
413000
3
ASSICURAZIONIASSO
425000
1
BIOGASSRL
487000
2
COMPUTERSHOP
506000
5
GASS.P.A.
25000
1
LIBRERIECULTURA
469000
2
SUPERMARCHETGS
150000
1

Abiti Bella compare nella tabella tre volte, Assicurazioni ASSO una volta,ecc.

Voglio sapere il totale dell’importo per ogni nota che facendo parte dello stesso beneficiariocompaia una o più volte.Voglio sapere quante volte quella stessa nota appare per lo stesso beneficiario. Voglio inoltre visualizzare le note:

SELECT BENEFICIARIO, NOTE, SUM(IMPORTO), COUNT(BENEFICIARIO)
FROM ASSEGNI
GROUP BY BENEFICIARIO, NOTE;

BENEFICIARIO
------------------------
NOTE
----------------------------
SUM(IMPORTO)
----------------------
COUNT(BENEFICIARIO)
---------------------------------
ABITIBELLA COMPLETODONNA
224000
1
ABITIBELLA PANTALONI
189000
2
ASSICURAZIONIASSO ASSICURAZIONECASA
425000
1
BIOGASSRL GAS
487000
2
COMPUTERSHOP CONTROLLER
122000
2
COMPUTERSHOP DISCHETTIECD-ROM
50000
1
COMPUTERSHOP JOYSTICK
134000
1
COMPUTERSHOP TELEFONOCELLULARE
200000
1
GASS.P.A. GAS
25 000
1
LIBRERIE CULTURA LIBRI, CANCELLERIA
469 000
2
SUPERMARCHET GS ALIMENTARI
150 000
1

Nella prima riga della tabella estrapolata con la query precedente, vediamo che COUNT(BENEFICIARIO) vale 1; ciò significa che la nota ‘Completo donna’ per quel beneficiario è presente nella tabella di origine una sola volta. Mentre invece, la nota ‘Pantaloni’, sempre per il medesimo beneficiario vale 2, questo significa che quella nota per quel beneficiario è presente nella tabella ben due volte.

Adesso vogliamo estrapolare i stessi dati della query precedente, ma ordinandoli per le note.

SELECT BENEFICIARIO, NOTE, SUM(IMPORTO), COUNT(BENEFICIARIO)
FROM ASSEGNI
GROUP BY BENEFICIARIO, NOTE
ORDER BY NOTE;

BENEFICIARIO
------------------------
NOTE
----------------------------
SUM(IMPORTO)
----------------------
COUNT(BENEFICIARIO)
---------------------------------
SUPERMARCHET GS ALIMENTARI
150 000
1
ASSICURAZIONI ASSO ASSICURAZIONE CASA
425 000
1
ABITI BELLA COMPLETO DONNA
224 000
1
COMPUTER SHOP CONTROLLER
122 000
2
COMPUTER SHOP DISCHETTI E CD-ROM
50 000
1
BIOGAS SRL GAS
487 000
2
GAS S.P.A. GAS
25 000
1
COMPUTER SHOP JOYSTICK
134 000
1
LIBRERIE CULTURA LIBRI, CANCELLERIA
469 000
2
ABITI BELLA PANTALONI
189 000
2
COMPUTER SHOP TELEFONO CELLULARE
200 000
1

Per gli esempi futuri faremo riferimento alla tabella DIPENDENTI sottostante:

DIPENDENTI
NOME
--------------------
DIVISIONE
-----------------------------
STIPENDIO
------------------
GIORNI_MUTUA
-------------------------
FERIE_GODUTE
-------------------------
ROSSI VENDITE
2 000 000
33
5
BIANCHI VENDITE
2 100 000
1
0
BRUNI RICERCA
3 300 000
0
9
VERDI ACQUISTI
1 800 000
32
20
GIALLI RICERCA
4 800 000
0
0
NERI RICERCA
3 400 000
2
1
MANCINI AMMINISTRAZIONE
2 400 000
9
24
MARCHETTI VENDITE
2 000 000
99
12

HAVING

Abbiamo visto come tramite la clausola GROUP BY le righe possano venire raggruppate in sottoinsiemi. Una particolare interrogazione può avere la necessità di estrapolare solo quei sottoinsiemi di righe che soddisfano certe condizioni, in questo caso però non è possibile usare la clausola WHERE in quanto tale clausola verifica la condizione che la segue, su tutte le righe e non in maniera singola sui valori estrapolati per ogni sottoinsieme di righe.
Vediamo un esempio:

Vogliamo conoscere le medie dei stipendi per ogni divisione che superano i 2.200.000 di lire

SELECT DIVISIONE, AVG(STIPENDIO)
FROM DIPENDENTI
GROUP BY DIVISIONE
WHERE AVG(STIPENDIO) > 2200000;

ERRORE alla riga 4:
ORA-00933: comando SQL terminato erroneamente

Nella query scritta sopra possiamo vedere come la clausola WHERE sia stata posta per ultima, infatti bisogna verificare la condizione solo dopo che sono stati formati i sottoinsiemi dalla clausola GROUP BY.
Il risultato però, è comunque un avviso di errore, proprio perché non è possibile utilizzare WHERE per verificare condizioni sui risultati di funzioni di gruppo. Vediamo quindi come possiamo risolvere il problema:

SELECT DIVISIONE, AVG(STIPENDIO)
FROM DIPENDENTI
HAVING AVG(STIPENDIO) > 2200000;

DIVISIONE
-------------------------------
AVG(STIPENDIO)
---------------------------
AMMINISTRAZIONE 2 400 000
RICERCA 3 833 333,3

Come abbiamo potuto vedere dall’esempio la clausola HAVING sostituisce la clausola WHERE la dove nella condizione appaiono funzioni di gruppo o quando la condizioni deve essere verificata su sottoinsiemi di righe.

Vediamo altri esempi:

SELECT DIVISIONE, AVG(STIPENDIO)
FROM DIPENDENTI
GROUP BY DIVISIONE
HAVING DIVISIONE = 'VENDITE';

DIVISIONE
-------------------------------
AVG(STIPENDIO)
---------------------------
VENDITE 2033333,3

In questo caso è stata estrapolata la media degli stipendi della sola divisione vendite. Proviamo a ottenere lo stesso risultato usando a posto della clausola HAVING la clausola WHERE:

SELECT DIVISIONE, AVG(STIPENDIO)
FROM DIPENDENTI
GROUP BY DIVISIONE
WHERE DIVISIONE = 'VENDITE';

ERRORE alla riga 4:
ORA-00933: comando SQL terminato erroneamente

Il risultato che si ottiene è un avviso di errore, in quanto la clausola WHERE è stata messa dopo la clausola GROUP BY e quindi si è tentato di usarla non per singole righe, ma per sottoinsiemi di righe. Vediamo come si può aggirare l’ostacolo senza, comunque, usare la clausola GROUP BY:

SELECT DIVISIONE, AVG(STIPENDIO)
FROM DIPENDENTI
WHERE DIVISIONE = 'VENDITE'
GROUP BY DIVISIONE;

DIVISIONE
-------------------------------
AVG(STIPENDIO)
---------------------------
VENDITE 2033333,3

In questo caso la clausola WHERE è stata usata non sugli insiemi delle righe, in quanto posta prima della clausola GROUP BY.

Voglio conoscere la media dei giorni di ferie godute per dipartimento, ma solo di quei dipendenti che percepiscono stipendi superiori ai 2.050.000 di lire:

SELECT DIVISIONE, AVG(FERIE_GODUTE)
FROM DIPENDENTI
WHERE STIPENDIO > 2050000
GROUP BY DIVISIONE;

DIVISIONE
-----------------------
AVG (FERIE_GODUTE)
---------------------------------------
AMMINISTRAZIONE 24
RICERCA   3,3333333
VENDITE   0

In questo caso abbiamo usato la clausola WHERE in quanto la condizione va verificata per tutte le righe e non per singoli valori estrapolati da singoli sottoinsiemi di righe.

Adesso vogliamo escludere dal risultato della query precedente quelle divisioni la cui media delle ferie godute, calcolata solo per quei dipendenti il cui stipendio supera i 2.050.000 di lire, è uguale a zero:

SELECT DIVISIONE, AVG(FERIE_GODUTE)
FROM DIPENDENTI
WHERE STIPENDIO > 2050000
GROUP BY DIVISIONE
HAVING AVG(FERIE_GODUTE) <> 0;

DIVISIONE
-----------------------
AVG (FERIE_GODUTE)
---------------------------------------
AMMINISTRAZIONE 24
RICERCA   3,3333333

Riepilogo

Dagli esempi precedenti, dalle cose che sono state dette e da eventuali esperimenti che potremmo fare, possiamo enunciare degli assiomi che riguardano l’uso delle clausole viste in questo capitolo:

  1. WHERE non può essere usato per verificare condizioni su risultati di funzioni di gruppo.
  2. WHERE non può essere usato per verificare condizioni su sottoinsiemi delle varie righe.

 

  1. GROUP BY tutte le colonne che vengono selezionate (colonne che seguono la clausola SELECT) devono essere elencate nella clausola GROUP BY.

 

  1. HAVING può essere seguita da una o più funzioni di gruppo e verificare condizioni su i valori ritornati. da tali funzioni.
  2. HAVING può verificare condizioni sui valori dei sottoinsiemi creati dalla clausola GROUP BY.
  3. HAVING può verificare condizioni combinate sui valori dei sottoinsiemi creati dalla clausola GROUP BY e condizioni sui valori ritornati da funzioni di gruppo.
  4. HAVING i campi che vi appaiono devono essere specificati nella clausola GROUP BY
  5. HAVING è necessario, per il suo utilizzo, la presenza della clausola GROUP BY.
  6. HAVING non è necessario che venga posta dopo la clausola GROUP BY.

 

  1. ORDER BY è necessario che venga posta dopo la clausola GROUP BY e dopo la clausola HAVING.

Riassumendo vediamo come può essere la forma sintetica di una query che fa uso delle clausole viste in questo capitolo:

select lista attributi o espressioni
from lista tabelle
[where condizioni semplici]
[group by lista attributi di raggruppamento]
[having condizioni aggregate]
[order by lista attributi di ordinamento]


 
Precedente
INDICE
Segue
pag. 8 di 20