SQL (Structured Query Language)

Un corso completo sul linguaggio SQL (Structured Query Language): definizioni, esempi ed esercizi

Clausole SQL

Capitolo 4

Le clausole SQL

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

  • WHERE
  • ORDER BY
  • GROUP BY
  • HAVING

 

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, ma a sottoinsiemi di esse. Vediamo un esempio:

Vogliamo sapere quanto è stato elargito, in totale, per ogni beneficiario:

SELECT BENEFICIARIO, SUM(IMPORTO)

FROM ASSEGNI

GROUP BY BENEFICIARIO;

BENEFICIARIO SUM(IMPORTO)
ABITI BELLA 334 000
ASSICURAZIONI ASSO 425 000
BIOGAS SRL 88 000
COMPUTER SHOP 418 000
GAS S.P.A. 25 000
LIBRERIE CULTURA 245 000
SUPERMARCHET GS 150 000

In questa query viene applicata la funzione di gruppo SUM per ogni sottoinsieme di BENEFICIARIO.

Da questo punto in poi dovremo considerare che alla tabella ASSEGNI sono stati aggiunti i seguenti record:

22 ABITI BELLA 79 000 PANTALONI
23 BIOGAS SRL 399 000 GAS
24 LIBRERIE CULTURA 224 000 LIBRI, CANCELLERIA
25 COMPUTER SHOP 88 000 CONTROLLER

Quindi la tabella così modificata apparirà nel seguente modo:

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
22 ABITI BELLA 79 000 PANTALONI
23 BIOGAS SRL 399 000 GAS
24 LIBRERIE CULTURA 224 000 LIBRI, CANCELLERIA
25 COMPUTER SHOP 88 000 CONTROLLER

È possibile applicare la clausola GROUP BY anche a più di un campo per volta. Vediamo come funziona:

SELECT BENEFICIARIO, NOTE

FROM ASSEGNI

GROUP BY BENEFICIARIO, NOTE;

BENEFICIARIO NOTE 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

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 ‘libri cancelleria’, ‘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)
ABITI BELLA 413 000 3
ASSICURAZIONI ASSO 425 000 1
BIOGAS SRL 487 000 2
COMPUTER SHOP 506 000 5
GAS S.P.A. 25 000 1
LIBRERIE CULTURA 469 000 2
SUPERMARCHET GS 150 000 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 beneficiario compaia 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)
ABITI BELLA COMPLETO DONNA 224 000 1
ABITI BELLA PANTALONI 189 000 2
ASSICURAZIONI ASSO ASSICURAZIONE CASA 425 000 1
BIOGAS SRL GAS 487 000 2
COMPUTER SHOP CONTROLLER 122 000 2
COMPUTER SHOP DISCHETTI E CD-ROM 50 000 1
COMPUTER SHOP JOYSTICK 134 000 1
COMPUTER SHOP TELEFONO CELLULARE 200 000 1
GAS S.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]

Autore: Art Net

Condividi questo articolo su

15 Commenti

  1. SAlve, quindi non esiste una funzione come p.e. in Excel, che estragga alcuni caratteri a destra o sinistra?
    Ho provato cn right(nome, 3) ma non lo riconosce

    Rispondi al Commento
  2. SELECT COUNT (*)
    Buongiorno

    FROM IMPIEGATO
    WHERE DIPARTIMENTO = ‘PRODUZIONE’

    genera il seguente errore:
    “The data types text and varchar are incompatible in the equal to operator”.

    Invece, sostituendo con WHERE DIPARTIMENTO LIKE ‘PRODUZIONE’, la query funziona.

    Rispondi al Commento
  3. Ho imparato alcune cose buone qui. Certamente merita il bookmarking per la rivisitazione.

    Mi chiedo quanti sforzi hai impostato per creare questo tipo di fantastico sito informativo.

    Rispondi al Commento
  4. guida molto interessante grazie se ci fossero anche le istruzioni per creare la tabella sarebbe completa secondo me

    Rispondi al Commento
  5. Grazie per la guida. Semplice, interessante ed utile.
    Vorremmo segnalare due cose. Un errore ed un dubbio.
    Errore:
    SELECT DIVISIONE, AVG(STIPENDIO)
    FROM DIPENDENTI
    HAVING AVG(STIPENDIO) > 2200000;

    manca la “group by DIVISIONE” prima della HAVING.

    Di conseguenza il dubbio sul punto 6.
    HAVING non è necessario che venga posta dopo la clausola GROUP BY.
    Sicuri?

    Rispondi al Commento
  6. Guida Molto utile, segnalo un errore nella query 9, capitolo 2, delle soluzioni:
    PrezzoIngrosso è moltiplicato * 1,5 ma si chiedeva un aumento del 15%, ciò significa moltiplicare * 1,15

    Rispondi al Commento
  7. Veramente complimenti, una guida dettagliata, semplice e adatta a tutti 🙂

    FortyZone

    Rispondi al Commento
  8. Davvero complimenti ragazzi. La prima guida che per chi parte da zero è manna dal cielo…PERFETTA!!

    Rispondi al Commento
  9. nel punto 8 la soluzione non dovrebbe essere con HAVING MIN(IMPORTO) > 400 000; cioè: SELECT BENEFICIARI FROM ASSEGNI GROUP BY BENEFICIARIO HAVING MIN(IMPORTO) > 400 000;

    Rispondi al Commento
  10. un ottimo Manuale unico errore (se vogliamo chiamarlo cosi) i tipi di dati Char(5) number(5,2) cosa sono e come si usano

    Rispondi al Commento
  11. Complimenti ottimo sito! fatto davvero bene. Grazie!

    Rispondi al Commento

Invia commento

Il tuo indirizzo email non sarà pubblicato.