MINI CORSO DI MICROSOFT ACCESS - parte 3°

PANNELLO QUERY

Con questo pannello vengono create le interrogazioni e gli ordinamenti sugli archivi. Rappresenta lo strumento di analisi dei dati. 

Alla base delle interrogazioni abbiamo un linguaggio chiamato SQL (Standard (structured) Query Language).

QUERY DI SELEZIONE

Le Query di selezione consentono:    

- di estrarre da una tabella solo alcune colonne 

- la creazione di elenchi ordinati

 - di selezionare, da una tabella, solo alcune righe in base alle condizioni specificate nella query stessa.

CREAZIONE DI UNA QUERY

Partendo dal ribbon "Crea" andiamo nella sezione "Query" e clicchiamo sull'icona "Struttura query".

Viene proposto l’elenco delle Tabelle o delle Query disponibili 

 

Facciamo doppio click su ogni tabella coinvolta nella nostra query. Man mano sullo sfondo appaiono le tabelle e le query selezionate. Chiudiamo al termine con l'apposito bottone "Chiudi".

Per selezionare i campi da visualizzare basta fare doppio click sul campo della tabella interessata (Zona A). Il primo posto disponibile nella zona B verrà occupato dal campo selezionato.

Notare lo * presente nella prima riga di ogni tabella. Se seleziono questa voce indico che di quella tabella intendo visualizzare tutti i campi.

Per eseguire una query basta cliccare sul bottone "Esegui" nel ribbon "Progettazione" / "Strumenti Query"

La zona B contiene l'elenco dei campi che la query visualizza

Analizziamo in dettaglio le singole voci di questa sezione:

Campo: In questa riga vengono indicati i campi da visualizzare.

Tabella: Le query possono coinvolgere più tabelle. Qui si specifica da quale tabella il campo selezionato è prelevato.

Ordinamento: con questa proprietà possiamo impostare se l'elenco (ottenuto con la query) debba essere ordinato in maniera crescente o decrescente rispetto al campo associato a quella colonna. L’ordinamento è uno dei principali motivi per cui si utilizzano le query.

Se intendo ordinare un elenco rispetto a più campi (es. elenco degli studenti per classe e per cognome) devo tener presente che il campo che viene ordinato per primo è quello che si trova più a sinistra. L’ordine dei campi che determinano l'ordinamento è quindi importante.

 

Nell'esempio qua sopra ordino l'elenco degli studenti prima per classe e poi, all'interno di ogni classe, per cognome.

In OpenOffice Base la stessa query all'interno dell'interfaccia grafica si presenta in questo modo:

Mostra: questa riga consente di nascondere il campo durante l'esecuzione della query. Solitamente viene utilizzato quando devo selezionare dei campi che risultano necessari:

- per specificare gli ordinamenti 

- per definire le condizioni di selezione 

e che non intendo visualizzare.  

Esempio 1: Ho una query che si chiama "Clienti di Brescia". Nella struttura di questa query avremo un vincolo per cui il campo "Provincia" deve essere pari alla stringa 'Brescia'. Visualizzare il nome della provincia durante l'esecuzione della Query è inutile poichè il nome della Query stessa è eloquente. Pertanto posso evitare di mostrare il campo provincia.

Esempio 2: Un altro caso dove questa proprietà è importante si ha quando l'ordine di visualizzazione dei campi è differente dall'ordine dei campi che determinano un ordinamento.

Esempio: devo ottenere un elenco di studenti dove il Nome appare in 1^ colonna, il Cognome in 2^ colonna e la Classe in 3^. L'ordinamento di questo elenco prevede prima la Classe e poi il Cognome.

IL LINGUAGGIO SQL

Per accedere al pannello di scrittura dei comandi SQL basta andare sulla barra del titolo di una query e richiamare mediante il tasto destro la voce "Visualizzazione SQL" del menu contestuale.

In OpenBase basta utilizzare, nel pannello "Ricerche", la voce "Crea ricerca in vista SQL ..."  

Menu equivalente di OpenOffice Base

Immaginiamo di avere a disposizione una  tabella CLIENTI con questi campi (in figura sono mostrate le definizioni  della tabella CLIENTI con Microsoft Access e con OpenOffice Base)

definizione con Microsoft Access definizione con OpenOffice Base 3.2

Qui sotto i comandi VBA per ricreare la tabella e i dati in Access

Public Function CreaDB()
Dim CmdSQL As String

   On Error Resume Next
   CurrentDb.Execute ("DROP TABLE Clienti")
   On Error GoTo 0
   CurrentDb.Execute("CREATE TABLE Clienti" & _
         "(" & _
         "  IdCliente LONG CONSTRAINT IdCliIdx PRIMARY KEY," & _
         "  [Ragione Sociale] TEXT(50) CONSTRAINT RagSocIdx NOT NULL, " & _
         "  Prov TEXT(2), " & _
         "  Fatturato SINGLE, " & _
         "  DataRag DateTime " & _
         ");")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (1,'Rossi Spa','BS',1000.21,#01/03/1964#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (2,'Verdi Srl','BG',390,#03/01/1981#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (3,'Gialli Snc','BS',7291,#03/01/1980#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (4,'La Ruspa Srl','BS',123,#03/01/2001#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (5,'Neri Spa','TN',23.29,#03/01/1999#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (6,'Ipermercato Snc','BG',129.03,#02/29/2000#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (7,'Casa Rotta Snc','BG',339.93,#03/28/2000#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (8,'Bianchi Sas','TN',23.29,#03/01/1999#);")
   CurrentDb.Execute ("INSERT INTO Clienti VALUES (9,'Rosa Camuna Spa','BS',1003.9,#03/12/2001#);")
End Function

Per eseguire il codice seguire questi passaggi:
a) premi la combinazione alt-F11;
b) menu "inserisci" voce "modulo";
c) incolla nella finestra tutto il codice VBA;
d) premi la combinazione Ctrl+G;
e) digita
call CreaDB e batti invio;
f) chiudi Access senza salvare e riaprilo oppure vai nel pannello delle "tabelle" e premi F5.

Clicca qui per scaricare invece il file di OpenBase.

LE QUERY DI SELEZIONE IN SQL

ORDINAMENTI

Esempio 1:

SeLeCt * FroM CLIENtI

Questo comando visualizza per intero la tabella clienti. Si noti che in SQL non è importante il minuscolo e il maiuscolo. 

SELECT è il comando SQL utilizzato per estrarre i dati (tipico delle query di selezione).

Esempio 2:

SELECT [Ragione Sociale] FROM CLIENTI

Estrae l’elenco delle ragioni sociale (nome della ditta) dalla tabella Clienti. Attenzione, quando il nome del campo ha uno spazio si devono usare le parentesi quadre (la [ si ottiene premendo contemporaneamente ALTGR è mentre ] ALTGR +).

OpenOffice Base utilizza come delimitatore per i nomi dei campi sia il doppio apice (") che l'apice inverso (si ottiene componendo il numero 96 con il tastierino numerico e  premendo contemporaneamente il tasto ALT). Quindi in OpenOffice Base il comando SQL

SELECT IdClienti, `Ragione Sociale` FROM Clienti

è equivalente a:

SELECT IdClienti, "Ragione Sociale" FROM Clienti

Esempio 3

SELECT [Ragione Sociale] AS NomeDitta FROM CLIENTI

Visualizza l’elenco delle ragioni sociali modificando l’intestazione del campo in NomeDitta. Le query consentono quindi di modificare in visualizzazione i nomi dei campi originali. Rinominare serve a rendere + comprensibile il contenuto dei risultati di una query. Si pensi ad un utente straniero che deve utilizzare il nostro archivio "Clienti". La parola ragione sociale per lui è chiaramente incomprensibile. Utilizzando questa tecnica posso creare degli elenchi con le intestazioni nella lingua dell’utente che dovrà consultare i nostri archivi rendendoli così comprensivi.

Esempio 4

SELECT [Ragione Sociale] AS Azienda, Prov FROM CLIENTI ORDER BY PROV

Elenca i clienti visualizzando il nome della ditta e la loro provincia il tutto ordinato per provincia.

La parola chiave ORDER BY viene utilizzata per specificare i campi da ordinare.  

Qualora i campi da ordinare fossero diversi basta elencarli separandoli con una virgola.

Esempio 5

SELECT * FROM CLIENTI ORDER BY PROV, [Ragione Sociale]

Questo comando SQL ordina per provincia e a parità di provincia ordina per Ragione Sociale.

L’ordine dei campi nella clausola sql ORDER BY è importante. Non è la stessa cosa scrivere l'esempio precedente così:

SELECT * FROM CLIENTI ORDER BY [Ragione Sociale],Prov

Se intendo fornire un elenco Clienti ordinato in maniera decrescente  per Ragione sociale devo scrivere:

SELECT * FROM CLIENTI ORDER BY [Ragione Sociale] DESC

Il tag DESC, utilizzato nella clausola ORDER BY, consente l’inversione dell’ordinamento (decrescente).

Attenzione: se durante l'esecuzione di una query vi viene chiesto  di immettere un valore allora significa che il vostro comando contiene il nome di un campo scritto in modo errato.

Il tag TOP n, utilizzato dopo la clausola SELECT, consente di visualizzare i record che occupano per primi la medesima posizione rispetto ad un determinato ordine. Se non è presente nella query la clausola  ORDER BY allora mostra semplicemente i primi n record ! Vediamo un esempio:

SELECT top 1 [Ragione Sociale], Prov from clienti order by prov

produce questo risultato

 

poichè:
- "BG" è la prima provincia (in ordine alfabetico) all'interno di Clienti
-
i clienti bergamaschi sono 3.

Se m è il numero di record visualizzati con TOP 1 allora TOP 2 ... TOP m produrranno sempre lo stesso elenco di record ovvero il comando SQL seguente:

SELECT top 3 [Ragione Sociale], Prov from clienti order by prov

produce ancora il risultato ottenuto con TOP 1:

Quando n supera m verranno aggiunti tutti i record che rispetto alla clausola di ordinamento occupano la stessa successiva posizione. Pertanto il comando:

SELECT top 4 [Ragione Sociale], Prov from clienti order by prov

restituisce questo output:

Ne consegue che TOP 4 ... TOP 7 producano sempre il medesimo risultato. Il ragionamento va applicato anche per i valori di n superiori. Ad esempio

SELECT top 8 [Ragione Sociale], Prov from clienti order by prov

restituisce questo output (idem anche TOP 9):

FILTRI

Partiamo con un esempio:

SELECT * FROM CLIENTI WHERE FATTURATO>100

Questa query estrae i clienti che hanno fatturato superiore a 100 Euro.

La clausola WHERE serve per creare un filtro sulle righe da visualizzare. La clausola WHERE è seguita dalla condizione che stabilisce le regole di selezione delle righe nella tabella. Verranno visualizzate solo le righe per le quali la condizione risulta VERA.

SELECT * FROM CLIENTI WHERE TRUE

Esempio 6

SELECT * FROM CLIENTI WHERE (FATTURATO>100) AND (FATTURATO<500)

Nell'esempio verranno mostrati tutti i clienti il cui fatturato risulta compreso tra 100 e 500 euro (estremi esclusi).

L’ordine di valutazione delle singole condizioni collegate dall'AND o dall'OR non è importante ai fini del calcolo dell'intera espressione condizionale quindi:

(Fatturato<50) OR (Fatturato >150)

è equivalente a

(Fatturato>150) OR (Fatturato <50)

Esempio 7:

Attenzione ad un uso corretto delle parentesi tonde. Infatti queste definiscono le precedenze con cui vanno valutate le singole condizioni presenti nella clausola WHERE.

Quindi scrivere (esempio 7A) 

SELECT * FROM CLIENTI WHERE ( (FATTURATO<100) OR (FATTURATO>500) ) AND (PROV=’BS’)

non è la stessa cosa di (esempio 7B)

SELECT * FROM CLIENTI WHERE (FATTURATO<100) OR ((FATTURATO>500) AND (PROV=’BS’))

Nel primo caso verranno visualizzati i clienti con fatturato non compreso tra 100 e 500 residenti a Brescia. Nel secondo caso invece verranno visualizzati i clienti con fatturato inferiore a 100 euro oppure quelli di Brescia con fatturato >500. 

In Access il singolo apice ' (usato nell'esempio 7 in corrispondenza del campo PROV) è utilizzato per identificare le costanti di tipo stringa. Le costanti di tipo stringa possono essere identificate anche con il doppio apice " per cui scrivere PROV='BS' è equivalente a PROV="BS".

In OpenOffice Base per identificare le costanti di tipo stringa si deve utilizzare obbligatoriamente il singolo apice ('). La scrittura PROV='BS' non è quindi equivalente a PROV="BS". Il doppio apice (") è il delimitatore per i nomi dei campi per cui in OpenOffice Base PROV="BS" è equivalente a PROV=BS.

L'operatore booleano AND  ha precedenza sull’OR (come lo * rispetto al + nelle operazioni algebriche) e pertanto l’interprete SQL risolve prima le condizioni legate dall'AND e successivamente le altre legate dall'OR.

Quindi considerando l'esempio  

SELECT * FROM CLIENTI WHERE (FATTURATO>100) AND (FATTURATO<500) OR (PROV=’BS’)

l'interprete SQL prima risolve 

(FATTURATO>100) AND (FATTURATO<500)

e successivamente legherà il risultato con l'OR (oppure) relativo alla provincia di Brescia.

L'uso delle parentesi può alterare la precedenza dell'AND rispetto all'OR. Eccone un esempio. 

SELECT * FROM CLIENTI  WHERE (FATTURATO>100) AND ((FATTURATO<500) OR (PROV='BS'))

La condizione ((FATTURATO<500) OR (PROV='BS')) è risolta per prima. Successivamente il risultato viene combinato con l'altra condizione associata all'AND

In generale le condizioni usate nella clausola WHERE hanno una sintassi del tipo:

Condizione1 <operatore1>  Condizione2 <operatore2> <operatoreN_1> CondizioneN

Esempio 9:

SELECT * FROM CLIENTI WHERE (DATAREG >= #05/27/2001#)

Questo esempio evidenzia la sintassi delle costanti di tipo data. Una data in un comando SQL va racchiusa tra #. Si noti la posizione del mese e del giorno che risultano invertite rispetto alla nostra notazione (tipico della datazione anglosassone).

In OpenOffice Base per identificare le costanti di tipo data/ora occorre utilizzare una sintassi particolare visibile nell'esempio seguente:

SELECT * FROM Clienti WHERE DataReg >= {D '2001-05-27' }

La lettera D implica che la stringa '2001-05-27' deve essere convertita in data/ora. Utilizzando l'interfaccia grafica "Crea ricerca in vista struttura ..." posso comunque utilizzare, in corrispondenza della riga dei "criteri", il carattere #

Esercizi:

1 - Costruire una query che consideri tutti i clienti di Brescia o di Bergamo e che hanno una data di registrazione compresa tra il 2 giugno e il 31 dicembre 2001

SELECT * FROM CLIENTI WHERE

((PROV='BS') OR (PROV='BG') )

AND ( (DATAREG<=#12/31/2001#) AND (DATAREG>=#06/02/2001#) )

2 – Costruire la query  che mi elenchi le sole Ragioni Sociali della tabella Clienti ordinate per provincia e con fatturato maggiore di 150 euro oppure minore di 50  

SELECT [Ragione Sociale] FROM CLIENTI WHERE (Fatturato<50) OR (Fatturato >150) ORDER BY PROV

Ricordatevi: le parentesi vanno controllate soprattutto quando l'espressione booleana del WHERE contiene operatori AND e OR contemporaneamente.

3 – Costruire la query che elenchi i clienti che iniziano per la lettera A ([ragione sociale] like 'A*') e con provincia uguale a BS o BG 

SELECT * FROM CLIENTI 

WHERE ([Ragione Sociale] like 'A*') AND

( (PROV='BS') OR (PROV='BG') )

RICERCHE CON L'OPERATORE LIKE

LIKE è un operatore molto simile all’uguale =

E’ utilizzato solo per campi di tipo stringa (testo e memo). Consente la ricerca per sottostringhe (esempio per controllare se una certa parola è presente in un certo campo).  

Esempio 10:

Se voglio visualizzare tutti i clienti che iniziano per A posso scrivere:

SELECT * FROM Clienti WHERE ([Ragione Sociale] LIKE  'A*')

In OpenOffice Base al posto di * si usa %. L'operatore LIKE è inoltre case sensitive per cui il comando SQL

SELECT * FROM Clienti WHERE "Ragione Sociale" LIKE 'A%'

estrae le aziende la cui Ragione Sociale inizia con la lettera A maiuscola.

Per rendere la ricerca case-insensitive si può fare ricorso alla funzione lower che rende le lettere tutte minuscole.

SELECT * FROM Clienti WHERE Lower("Ragione Sociale") LIKE 'a%'

oppure alla funzione upper che rende tutte le lettere maiuscole:

SELECT * FROM Clienti WHERE UppER("Ragione Sociale") LIKE 'A%'

Altra alternativa è definire come tipo di dato per il campo soggetto alla ricerca il tipo "VARCHAR_IGNORECASE" invece di "VARCHAR".

Esempio 11:

Se voglio trovare tutti i Clienti la cui Ragione Sociale termina per 'SPA'  (Società per azioni) posso scrivere:

SELECT * FROM Clienti WHERE ([Ragione Sociale] LIKE  '*SPA')  

Con questa clausola vengono visualizzate le aziende con ragione sociale come: 'ROSSI SPA', 'Bianchi SpA'. E' esclusa la ditta  'La Ruspa Srl'.

Esempio 12:

Se intendo visualizzare i clienti la cui ragione sociale contiene la parola CASA scrivo:

SELECT * FROM Clienti WHERE ([Ragione Sociale] LIKE  '*CASA*')    

Attenzione nello standard SQL il carattere * è sostituito con il carattere %

Esempio 13:

Immaginiamo di creare una query di questo tipo e di salvarla:

SELECT *

FROM Clienti

WHERE ([Ragione Sociale] like [dammi la lettera iniziale] & "*");

Adesso il pannello Query contiene la query appena salvata. Proviamo ad aprirla.

Lanciandola (eseguendola) ACCESS non trova alcun riferimento a [dammi la lettera iniziale]. Mediante la finestra di dialogo qui sopra Access chiede all'utente di valorizzarla. L'utente, leggendo la richiesta, non fa altro che scrivere la lettera iniziale.

La scelta di una frase opportuna racchiusa tra [] rende chiaro il significato di ciò che si vuol ricevere come informazione dall'utente. 

Al posto di [dammi la lettera iniziale] potevo utilizzare qualsiasi sequenza di caratteri; ad esempio [Pluto]. Al momento dell'esecuzione della query la richiesta di valorizzare [Pluto] lascia perplesso l'utente  che non intuisce il significato del valore richiesto.

In OpenOffice Base per richiedere la valorizzazione di un parametro si utilizza una sintassi differente:

SELECT * FROM Clienti
where "Ragione Sociale" like concat(:dammi_la_lettera_iniziale,'%')

In OpenOffice Base i parametri vengono definiti facendo precedere il nome del parametro da due punti (:). L'esecuzione della query richiede la valorizzazione dei parametri presenti nel comando SQL.

Altra osservazione in merito a questo esempio è l'utilizzo dell'operatore &  o di concatenazione di stringhe:

esempio:

"Ciao " & "Marco" diventa "Ciao Marco"

& corrisponde al + delle espressioni algebriche ma viene utilizzato per unire 2 stringhe in una sola.

Attenzione: l'& non è un operatore commutativo ovvero

'Ciao ' & 'Paola' è 'Ciao Paola'

'Paola' & 'Ciao ' è 'PaolaCiao '

Esempio 14:

Consideriamo una tabella Alunni dove i campi Nome e Cognome risultano distinti. Se voglio creare una query che li unisca posso procedere in questo modo

SELECT (Cognome & ' ' &  Nome) AS Nominativo From ALUNNI

Lo ' ' (2 singoli apici separati da uno spazio) è usato per separare il Cognome dal Nome.

In OpenOffice Base per concatenare le stringhe occorre utilizzare la funzione Concat che accetta due argomenti di tipo stringa e restituisce la stringa ottenuta concatenando (mettere in sequenza) i suoi due argomenti. In HSQL quindi la query sugli alunni diventa:

SELECT Concat(Concat(Cognome,' '),Nome) AS Nominativo FROM Alunni

LA SINTASSI DEI COMANDI SELECT  

SELECT

[NOME DEI CAMPI DA VISUALIZZARE  SEPARATI DALLA VIRGOLA]

FROM [ELENCO TABELLE DOVE PRELEVO I DATI SEPARATE DALLA VIRGOLA]

WHERE [CONDIZIONI LEGATE DA AND ED OR] 

ORDER BY [ELENCO DEI CAMPI DI ORDINAMENTO SEPARATI DALLA VIRGOLA]

QUERY STATISTICHE O DI RAGGRUPPAMENTO

Con questo tipo di query è possibile ottenere delle statistiche sulle tabelle. Ad esempio posso stabilire quanti libri sono stati prestati in un certo periodo, quanto è il fatturato di una azienda distinto per provincia etc. Iniziamo considerando quelle statistiche che riguardano la globalità dell'archivio. La sintassi per questo tipo di query di raggruppamento risulta semplificata ed esattamente:

SELECT Funzione(NomeCampo) AS NomeDaVisualizzare FROM NomeTabella

Dove Funzione è una particolare statistica. L'elenco completo di queste funzioni verrà dato  successivamente:

Esempio 15:

SELECT Count(*) AS NumeroClienti FROM CLIENTI

Questa query utilizza la funzione Count che effettua un conteggio. Il risultato è il numero di clienti presenti nella tabella  CLIENTI.

Esempio 16:

SELECT Max(Fatturato) AS MassimoFatturato

FROM CLIENTI

Questa query fornisce il massimo fatturato realizzato.

Esempio 17:

SELECT Min(DataReg) AS PrimaRegistrazione

FROM CLIENTI

Restituisce la data della prima registrazione.

Esempio 18:

SELECT Avg(Fatturato) AS FatturatoMedio

FROM CLIENTI

Calcola il fatturato medio globale

Esempio 19:

SELECT Sum(Fatturato) AS TotaleIncassato FROM CLIENTI

Calcola il fatturato totale dell’azienda.

Le Query viste si basano su particolari funzioni statistiche ed esattamente:

n            SUM(NomeCampo) à Somma dei valori contenuti in NomeCampo

n            AVG(NomeCampo) à Media (average) dei valori contenuti in NomeCampo

n            STDEVP(NomeCampo) à Deviazione standard (o scarto quadratico medio) dei valori contenuti in NomeCampo. Questo parametro rappresenta un indice della variabilità dei valori contenuti in un campo di una tabella rispetto al loro valore medio. Maggiore è il valore della deviazione standard maggiori sono le variazioni dei valori rispetto alla media. Al contrario una sequenza composta sempre dallo stesso valore (sequenza costante) avrà una deviazione standard nulla poichè la distanza di ogni singolo valore rispetto alla media è zero. Altre funzioni statistiche, alternative a STDEVP, disponibili in Access sono:
- VAR(NomeCampo) che restituisce la varianza
- STDEV(NomeCampo) che restituisce la deviazione standard corretta.
Per approfondire l'argomento relativo alla deviazione standard clicca qui.

n            MAX(NomeCampo) à Valore massimo contenuto in NomeCampo

n            MIN(NomeCampo) à Valore minimo contenuto in NomeCampo

n            COUNT(*) o COUNT(NomeCampo) à Conteggia il numero di schede che sono presenti in una tabella. Usando la clausola WHERE calcolo il numero di record che soddisfano una certa condizione. Si noti che mettere * o un nome di un campo come argomento nella funzione  COUNT è la stessa cosa. 

n            FIRST(NomeCampo) à Visualizza il valore contenuto in NomeCampo della 1^ scheda registrata della tabella  (in assenza della clausola order by)

n            LAST(NomeCampo) à Visualizza il valore contenuto nell’ultima scheda della tabella nel campo NomeCampo (in assenza della clausola order by)

In alcuni casi le statistiche non riguardano la globalità della tabella ma si riferiscono ai valori possibili contenuti in un singolo campo: si pensi ad esempio ad un elenco che visualizzi il numero di abitanti per regione.  

Un altro esempio è fornire il numero di studenti per classe partendo da una tabella contenente l’elenco di tutti gli alunni iscritti in un istituto scolastico. (è sostanzialmente una statististica rispetto a qualche raggruppamento).

Per questo tipo di statistiche  la costruzione del comando SQL segue questa sintassi:

SELECT NomeCampoRaggruppato, Funzione(NomeCampoRaggruppato) 
FROM
NomeTabella 
[WHERE Condizione1 operatoreLogico1 ...] 
GROUP BY
NomeCampoRaggruppato
[ORDER BY NomeCampoRaggruppato]
[HAVING CondizioneSuFunzioneRaggruppamento operatoreLogicoA ...

Esempio 20:

Se voglio conoscere il numero di clienti per provincia posso scrivere:

SELECT Provincia, Count(*) AS Numero 
FROM Clienti GROUP BY Provincia

Il  risultato ottenuto eseguendo questa query è:

Esempio 21:

Si consideri la seguente tabella studenti:

Posso contare il numero di studenti per classe con questa query:

SELECT Classe, Count(*) AS [Numero studenti]
FROM Studenti
GROUP BY Classe
ORDER BY Classe

che eseguita restituisce questo risultato

Se voglio visualizzare il numero di studenti di ogni classe del quarto anno devo modificare la query in questo modo:

SELECT Classe, Count(*) AS [Numero studenti]
FROM Studenti
WHERE Classe like "4*"
GROUP BY Classe
ORDER BY Classe

La sua esecuzione mostra questo risultato

Se invece desidero elencare le classi che hanno più di 28 alunni devo impostare la seguente query:

SELECT Classe, Count(*) AS [Numero studenti]
FROM Studenti
GROUP BY Classe
HAVING (Count(*)>28)
ORDER BY Classe;

che genera il seguente elenco

Infine se voglio elencare le classi della sezione "T" che hanno più di 28 alunni devo scrivere questa query:

SELECT Classe, Count(*) AS [Numero studenti]
FROM Studenti
WHERE Classe like "*T"
GROUP BY Classe
HAVING (Count(*)>28)
ORDER BY Classe;

che eseguita produce questo elenco

In merito alle direttive Where ed Having è necessario ora fare delle precisazioni per illustrare quando vanno utilizzate.

Partiamo dalla seguente query che fornisce il medesimo risultato della query precedente ma non è corretta ed inoltre risulta più lenta

SELECT Classe, Count(*) AS [Numero studenti]
FROM Studenti
GROUP BY Classe
HAVING (Count(*)>28)
AND Classe like "*T"
ORDER BY Classe;

Gestendo il filtro sulle classi della sezione "T" mediante la direttiva Having costringo il database ad applicare il Group By sull'intero archivio B=A.

 

Poichè l'operazione di raggruppamento rappresenta l'operazione più pesante in termini computazionali ne consegue un aumento dei tempi di risposta dovuto al maggior numero di record B da analizzare. Il filtro gestito dalla direttiva Having si limita a mostrare/nascondere i risultati C della statistica producendo un risultato finale D che non incide mai in modo sensibile sui tempi di esecuzione complessivi.

Se invece utilizzo la query corretta:

SELECT Classe, Count(*) AS [Numero studenti]
FROM Studenti
WHERE Classe like "*T"
GROUP BY Classe
HAVING (Count(*)>28)
ORDER BY Classe;

la direttiva Where effettua una selezione dell'insieme originale dei record A restituendo solitamente un insieme numericamente inferiore B composta da quei record che soddisfano la condizione α.

Questo filtro riduce i dati su cui viene applicata l'operazione di raggruppamento e quindi il risultato intermedio C può essere prodotto in un tempo inferiore rispetto a quello necessario per raggruppare l'intero insieme dei record A. La direttiva Having, come già citato in precedenza, si limita a filtrare i risultati del Group By C mostrando solo le righe D che soddisfano la condizione β: il tutto senza incidere in modo significativo sui tempi di esecuzione complessivi.

Quindi per garantire massime performance è preferibile applicare subito tutti i filtri richiesti (tramite la direttiva Where) al fine di diminuire la quantità di record su cui applicare il Group By riducendo il carico di lavoro associato all'operazione di raggruppamento che rappresenta la componente computazionale che incide maggiormente sui tempi di esecuzione complessivi della query.

I filtri sulle funzioni statistiche (calcolate dopo il Group By) devono essere obbligatoriamente applicati solo dopo l'operazione di raggruppamento e pertanto non possono essere applicati sull'insieme originale dei record A (clausola Where) ma solo sul risultato del Group By C quindi tramite la clausola Having.

Riassumendo nelle query di raggruppamento i filtri sulle funzioni statistiche devono essere gestiti con la direttiva Having mentre tutti gli altri casi devono essere trattati con la clausola Where.