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 |
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.
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.
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 |
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 |
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:
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]
pag. 8 di 20 |