Data ultimo aggiornamento: 13/06/2012

Clicca per accedere al sito di NTS Informatica
Clicca per accedere all'argomento Clicca per accedere all'argomento Clicca per accedere all'argomento Clicca per accedere all'argomento
Clicca per accedere al sito di NTS Informatica

Fondamenti del linguaggio SQL e l'istruzione SELECT in dettaglio

Il Linguaggio SQL, diventato ormai uno standard mondiale per formulare interrogazioni strutturate a database relazionali, incorpora molti costrutti (o istruzioni) oltre a quella principale denominata SELECT, ma per non divagare in discorsi che potrebbero risultare complessi se trattati in maniera approfondita, limiteremo la trattazione alla sola istruzione di selezione, rimandando l'utente che ne volesse sapere di più, alla consultazione di libri o manuali specifici su SQL, oppure su Microsoft Access.

L'istruzione SELECT (in italiano, SELEZIONA) permette di indicare a Business quali dati (Es.: Descrizione, Prezzo, Codice, Quantità, Data, etc.), relativi a una o più entità (Es.: Cliente, Articolo, Ordine, etc.), prelevare dagli archivi, se e come filtrarli (Es.: "solo quelli di Rimini" oppure "solo quelli che costano più di 10000 £", etc.), sulla base di quale dato presentarli in maniera ordinata e/o raggruppata. Di seguito ne è riportata la sintassi:

SELECT NomeCampo1, NomeCampo2,....,NomeCampoN
FROM NomeTabella
WHERE Condizione
GROUP BY NomeCampo1, NomeCampo2,....,NomeCampoL
HAVING Condizione
ORDER BY NomeCampo1,NomeCampo2,....,NomeCampoM

Supponiamo esistente una tabella, semplificata rispetto a quella esistente in Business, di nome TbClienti e contenente informazioni sui Clienti e formata dalle seguenti informazioni: Cognome, Nome, Indirizzo, Cap, Città, Provincia, Telefono.

Di seguito è riportato un possibile schema della tabella TbClienti:

TbClienti

Cognome Nome Indirizzo Cap Città Provincia Telefono
Rossi Mario Via Mimmo, 12 00100 Roma RM 06/xxxxxx
Bianchi Valerio Via Mommi, 21 00?00 Milano MI 02/yyyyyy
Verdi Giuseppe Via Rossini, 34 00800 Pesaro PS 0721/zzzzzz
Blu Marina Via Rosa, 23 47036 Riccione RN 0541/hhhhhh

Ogni riga di questa tabella, eccetto la prima presente solo per motivi descrittivi, rappresenta un record (cioè un gruppo di informazioni relative alla stessa entità, nell'esempio "un Cliente") formato a sua volta da Campi (rappresentati nell'esempio dalle colonne, che specificano le informazioni disponibili per ogni record: Cognome, Nome, Indirizzo, Cap, Città, Provincia, Telefono). Fondamentalmente possiamo pensare gli archivi di Business molto prossimi a questa struttura (cioè una Tabella), con la differenza che il numero delle tabelle è di parecchie decine, e il numero di Campi per ogni tabella varia da 2 a 100 circa.

Una SELECT può essere vista come una operazione che prende in ingresso 1 o più tabelle, e ne restituisce una, contenente i risultati della nostra richiesta (Tabella Risultato). Creiamo, ora, una piccola Query (in italiano, INTERROGAZIONE; che non è altro che una istruzione SELECT): specifichiamo la parola chiave SELECT, seguita dal nome dei campi della tabella ( o Tabelle) che vogliamo siano visualizzati nella 'Tabella Risultato'.

SELECT Cognome,Nome,Telefono

seguiti dalla clausola FROM (in italiano, Da) e il nome della o delle Tabelle a cui appartengono i campi elencati dopo la SELECT (fatto che rende importante conoscere la struttura delle tabelle del database di Business):

SELECT Cognome,Nome,Telefono
FROM TbClienti

Indicati quali campi vogliamo vedere e stabilite le tabelle a cui questi campi appartengono, abbiamo già fornito le indicazioni minime indispensabili per poter eseguire la query. Il risultato di questa query sarà una tabella ('Tabella Risultato') avente lo stesso numero di record (righe) della tabella TbClienti, ma solo 3 dei 7 campi della tabella TbClienti (abbiamo, cioè, limitato la visualizzazione di informazioni relative ad ogni cliente (riga) e NON, attenzione, al numero di clienti (righe) che rimane sempre 4) .

Ecco, di seguito, la 'Tabella Risultato' della query:

Cognome Nome Telefono
Rossi Mario 06/xxxxxx
Bianchi Valerio 02/yyyyyy
Verdi Giuseppe 0721/zzzzzz
Blu Marina 0541/hhhhhh

Supponiamo ora di voler vedere le stesse informazioni ma dei soli Clienti della provincia di Rimini:

SELECT Cognome,Nome,Telefono
FROM TbClienti
WHERE Provincia = 'RN'

Ed ecco il risultato di questa nuova query:

Cognome Nome Telefono
Blu Marina 0541/hhhhhh

a tal fine abbiamo utilizzato la clausola WHERE (in italiano, Dove) attraverso cui possiamo indicare anche più condizioni (o filtri) nello stesso modo utilizzato per i Filtri Utente:

SELECT Cognome,Nome,Telefono
FROM TbClienti
WHERE Provincia = 'RN' OR Provincia = 'MI'

In questo caso, insieme ai Clienti della provincia di Rimini, verranno visualizzati nella 'Tabella Risultato' anche i clienti della provincia di Milano. (OR = oppure).

Cognome Nome Telefono
Bianchi Valerio 02/yyyyyy
Blu Marina 0541/hhhhhh

Se proviamo a leggere la query traducendo le sue clausole in italiano, notiamo che è un linguaggio abbastanza naturale dal punto di vista della comprensione: - "SELEZIONA Cognome,Nome,Telefono DA TbClienti DOVE Provincia UGUALE 'RN' OPPURE Provincia UGUALE 'MI'".

Una istruzione di SELECT può, come abbiamo già detto, selezionare dati anche da più tabelle contemporaneamente. Facciamo un esempio, supponendo esistenti 2 tabelle così strutturate:

TbDipendenti

CodiceDipendente Cognome Nome Stipendio CodiceReparto
D1 Rossi Mario 1.700.000 R1
D2 Verdi Pino 1.800.000 R2
D3 Rosa Maria 1.500.000 R1
D4 Bianchi Barbara 2.000.000 R2

TbReparti

CodiceReparto Descrizione Orario CapoReparto
R1 Produzione Intero Pinco
R2 Controllo Q. Ridotto Pallino

La Tabella TbDipendenti contiene il campo 'Codice del Dipendente', affinchè ogni dipendente sia univocamente identificato (anche in caso di omonimia), il campo 'Cognome', il campo 'Nome' e il campo 'Codice del Reparto' presso cui il Dipendente è impiegato. La Tabella TbReparti contiene il campo 'Codice del Reparto', il Campo 'Descrizione del Reparto', il campo 'Orario' e il campo 'Cognome del Capo-reparto'.

Proviamo a scrivere una query semplice:

SELECT TbDipendenti.Cognome, TbReparti.Descrizione, TbReparti.CapoReparto
FROM TbDipendenti, TbReparti

Riportiamo di seguito il risultato della query:

TbDipendenti.Cognome TbReparti.Descrizione TbReparti.CapoReparto
Rossi Produzione Pinco
Verdi Produzione Pinco
Rosa Produzione Pinco
Bianchi Produzione Pinco
Rossi Controllo Q. Pallino
Verdi Controllo Q. Pallino
Rosa Controllo Q. Pallino
Bianchi Controllo Q. Pallino

Premettiamo che il risultato potrebbe apparire poco significativo, in quanto il programma, che ha elaborato la nostra query, si è limitato, giustamente, a fornire tutte le combinazioni possibili dei record della tabella TbDipendenti con quelli della tabella TbReparti (il cliente 'Rossi' combinato prima con il Reparto 'Produzione' e poi col Reparto 'Controllo Q' e stessa cosa per i restanti 3 clienti), visualizzando poi solo i valori dei campi che noi abbiamo elencato di seguito alla parola chiave SELECT (TbDipendenti.Cognome, TbReparti.Descrizione, TbReparti.CapoReparto). I Record ritornati nella 'Tabella Risultato' sono 8, ottenuti, infatti, dai 4 della Tabella TbDipendenti combinati (quindi moltiplicati) con i 2 della Tabella TbReparti. Tecnicamente si dice che viene restituito il 'Prodotto Cartesiano' delle n Tabelle elencate nella clausola FROM.

Tenendo presente questo meccanismo, in base al quale ogni volta che nella clausola FROM (Da) appaiono due o più tabelle, il risultato sarà una combinazione di tutti i record della prima con tutti quelli della seconda, proviamo, immediatamente, a costruire una Query più significativa: supponiamo di voler sapere in che reparto lavora la Sig.ra Bianchi:

SELECT TbReparto.CodiceReparto, TbReparto.Descrizione
FROM TbDipendenti, TbReparti
WHERE TbDipendenti.Cognome="Bianchi" AND TbDipendenti.CodiceReparto = TbReparti.CodiceReparto

Di seguito è riportato il risultato della query appena descritta:

TbReparto.CodiceReparto TbReparto.Descrizione
R2 Controllo Q.

I campi riportati sono due (TbReparto.CodiceReparto, TbReparto.Descrizione), perché due sono i campi listati di seguito alla istruzione SELECT. Da notare che al nome dei campi (CodiceReparto, Descrizione) è stato fatto precedere il nome della tabella separata da un punto("TbReparto."), per evitare errori qualora ci siano campi con nomi uguali, appartenenti a tabelle diverse (come nel nostro caso con CodiceReparto, presente in entrambe le tabelle TbReparti e TbDipendenti). Si consiglia di utilizzare sempre questa convenzione. Nella clausola FROM (Da), invece, troviamo elencati i nome delle due tabelle, anche se non richiediamo alcuna visualizzazione dei campi della tabella TbDipendenti; ciò perché abbiamo bisogno di avere tutte le combinazioni fra le due tabelle, come nell'esempio precedente, da cui, poi, selezionare solo quelle che ci interessano ai fini dell'ottenimento del risultato che ci aspettiamo. Infatti per poter selezionare i soli dati relativi alla Signora Bianchi, abbiamo specificato che il campo Cognome, che è un campo di TbDipendenti, deve essere uguale a "Bianchi" (quindi, saranno scartate tutte le combinazioni NON aventi nel campo TbDipendenti.Cognome il valore 'Bianchi'). La seconda condizione, unita alla prima tramite l'operatore logico "AND", viene tecnicamente chiama "JOIN" cioè "Collegamento". è, infatti, quest'ultima, che ci permette di visualizzare la Descrizione associata al CodiceReparto 'R2' che è il valore presente anche, nel campo CodiceReparto del record relativo alla Signora 'Bianchi' nella tabella TbDipendenti. Possiamo dire, in altre parole, che la Join "collega" i dati della tabella TbDipendenti con i relativi e corrispondenti dati della TbReparti (costringe, cioè, il motore SQL a scartare tutte quelle combinazioni di record delle due tabelle in cui NON si ha che il CodiceReparto di TbDipendenti sia UGUALE al CodiceReparto di TbReparti).

Proviamo, ora, a richiedere Nome e Cognome di tutti i dipendenti che lavorano nel reparto 'Produzione'.

SELECT TbDipendenti.Cognome, TbDipendenti.Nome
FROM TbDipendenti, TbReparti
WHERE TbReparti.Descrizione = 'Produzione' AND TbDipendenti.CodiceReparto = TbReparti.CodiceReparto

Quanto segue, ne costituisce il risultato:

TbDipendenti.Cognome TbDipendenti.Nome
Rossi Mario
Rosa Maria

Nella SELECT è stato richiesto il contenuto dei campi Cognome e Nome della tabella TbDipendenti. Nella Clausola FROM (Da) sono state nuovamente specificate entrambe le tabelle, affinchè il programma esegua il 'Prodotto Cartesiano' tra le tabelle in questione. Nella Clausola WHERE (Dove) troviamo la solita JOIN (collegamento), che collega la tabella TbDipendenti con la tabella TbReparti attraverso il campo CodiceReparto (ma che praticamente non è altro che la condizione che scarta tutte le combinazioni in cui TbDipendenti.CodiceReparto e TbReparti.CodiceReparto sono diversi), e la condizione che impone la selezione di tutte e solo le combinazioni di record che hanno nel campo TbReparti.Descrizione il valore 'Produzione'.

Se alla query precedente aggiungiamo la clausola ORDER BY (in italiano, ORDINATE PER), è possibile variare l'ordine di visualizzazione dei record nella 'Tabella Risultato'. Es.:

SELECT TbDipendenti.Cognome, TbDipendenti.Nome
FROM TbDipendenti, TbReparti
WHERE TbReparti.Descrizione = 'Produzione' AND TbDipendenti.CodiceReparto = TbReparti.CodiceReparto
ORDER BY TbDipendenti.Cognome, TbDipendenti.Nome

In questo modo la 'Tabella Risultato' sarà ordinata in base al campo Cognome, e in caso di uguaglianza del campo Cognome, in base al campo Nome e in caso di uguaglianza anche del Campo Nome, in ordine di disposizione nelle tabelle di origine (TbDipendenti).

TbDipendenti.Cognome TbDipendenti.Nome
Rosa Maria
Rossi Mario

L'ultima Clausola applicabile, è quella denominata GROUP BY (in italiano, RAGGRUPPATI PER). Essa ci permette di raggruppare i record (righe) in base a campi che hanno gli stessi valori e attraverso la sotto-clausola HAVING (in Italiano, AVENTI) eliminare i raggruppamenti che non ci interessano. In altre parole, occorre utilizzare la clausola WHERE (Dove) per escludere le righe che non si desidera raggruppare e occorre utilizzare la clausola HAVING (Aventi) per filtrare i record dopo che sono stati raggruppati.Es:

SELECT TbReparti.Descrizione, SUM(TbDipendenti.Stipendio)
FROM TbDipendenti, TbReparti
WHERE TbDipendenti.CodiceReparto = TbReparti.CodiceReparto
GROUP BY TbReparti.Descrizione

Attraverso la Query precedente si ottiene, un raggruppamento dei dipendenti per reparto di lavoro e attraverso la funzione SUM(stipendio) si ottiene la somma degli stipendi dei dipendenti raggruppati per reparto. Le funzioni tipo SUM (Avg, Count, Min, Max) non sono attualmente inseribili tramite il Generatore di Query. Nell'eventualità, è lasciato all'utente il compito di inserirlo manualmente.

TbReparti.Descrizione SUM(stipendio)
Controllo Q. 3.800.000
Produzione 3.200.000

La sintassi delle condizioni inseribili nella clausola HAVING (Aventi) rispondono alle stesse regole delle condizioni della clausola WHERE (Dove), con la differenza che possono essere oggetto di condizione solo i Campi elencati dopo la Clausola GROUP BY (Raggruppati per).

Clicca per accedere al sito di NTS Informatica