Raggruppare le tabelle: JOIN
Nell'introduzione a questa guida abbiamo definito MySQL come un database relazionale poiché, mediante le opportune query, è capace di mettere in relazione le tabelle presenti in un database. Abbiamo fatto l'esempio che i movimenti potrebbero essere inseriti non mediante il nome (assegno, bonifico, versamento) ma mediante un ID (1=assegno, 2=bonifico,3 = versamento).
La relazione tra la tabella movimenti e la tabella tipi_movimento e tra la tabella movimenti e la taballa clienti può essere fatta usando le funzioni di aggregazione JOIN. Prima di proseguire facciamo un riepilogo delle nostre tabelle.
Adesso dobbiamo inserire alcune tipologie di movimento fittizie nella tabella tipi_movimento.
INSERT INTO `tipi_movimento` (ID, `tipo`, `descrizione`) VALUES (1, 'entrata', 'Versamento in contanti'); INSERT INTO `tipi_movimento` (ID, `tipo`, `descrizione`) VALUES (2, 'uscita', 'Prelievo in contanti'); INSERT INTO `tipi_movimento` (ID, `tipo`, `descrizione`) VALUES (3, 'entrata', 'bonifico'); INSERT INTO `tipi_movimento` (ID, `tipo`, `descrizione`) VALUES (4, 'uscita', 'bonifico'); INSERT INTO `tipi_movimento` (ID, `tipo`, `descrizione`) VALUES (5, 'entrata', 'assegno'); INSERT INTO `tipi_movimento` (ID, `tipo`, `descrizione`) VALUES (6, 'uscita', 'assegno');
A questo punto possiamo inserire una serie di ipotetici movimenti nella tabella movimenti
INSERT INTO movimenti (ID_cliente, tipo, data, valuta) VALUES ('1', '1', '2008-08-09 09.00.00', 2500); INSERT INTO movimenti (ID_cliente, tipo, data, valuta) VALUES ('1', '4', '2008-08-09 09.00.00', 2500); INSERT INTO movimenti (ID_cliente, tipo, data, valuta) VALUES ('1', '6', '2008-08-10 09.00.00', 4500); INSERT INTO movimenti (ID_cliente, tipo, data, valuta) VALUES ('3', '2', '2008-08-11 09.00.00', 500);
Abbiamo detto che c'è una relazione tra ID_cliente della tabella movimenti ed ID della tabella clienti e una relazione tra tipo della tabella movimenti ed ID della tabella tipi_movimento. Per avere il nome del cliente ed il tipo di operazione possiamo usare una JOIN tra tabelle.
SELECT movimenti.ID, movimenti.data, movimenti.valuta, clienti.nome,clienti.cognome, tipi_movimento.descrizione, tipi_movimento.tipo FROM movimenti JOIN tipi_movimento ON tipi_movimento.ID = movimenti.tipo JOIN clienti ON clienti.ID = movimenti.ID_cliente WHERE movimenti.ID = 1;
+----+---------------------+----------+-------+---------+------------------------+---------+
| ID | data | valuta | nome | cognome | descrizione | tipo |
+----+---------------------+----------+-------+---------+------------------------+---------+
| 1 | 2008-08-09 09:00:00 | 2500.000 | Mario | Rossi | Versamento in contanti | entrata |
+----+---------------------+----------+-------+---------+------------------------+---------+
1 row in set (0.00 sec)
La query precedente ha svoltuo diverse operazioni. Per prima cosa ha selezionato dalla tabella movimenti i campi ID, data, valuta, dalla tabella clienti i campi nome e cognome e dalla tabella tipi_movimenti il campo descrizione. La selezione dei vari campi necessariamente deve essere fatta nella forma nometabella.nomecampo poiché MySQL non può stabilire a quale tabella si riferisce il campo; questo è uno dei motivi principali per cui quando si assegna un nome ad una tabella non si dovrebbe mai usare il punto. Analizzando la query notiamo le JOIN che metteno in relazione, rispettivamente, la tabella tipi_movimento su (ON) tipi_movimento.ID con movimento.tipo. L'altra JOIN mette in relazione la tabella clienti su clienti.ID con movimenti.ID_cliente. La clausola WHERE finale determina che vogliamo visualizzare il movimento avente ID 1.
Se volessimo vedere tutti i movimenti di Mario Rossi, visto che il suo ID è 1, dovremmo aggiustare la query.
SELECT movimenti.ID, movimenti.data, movimenti.valuta, clienti.nome, clienti.cognome, tipi_movimento.descrizione, tipi_movimento.tipo FROM movimenti JOIN tipi_movimento ON tipi_movimento.ID = movimenti.tipo JOIN clienti ON clienti.ID = movimenti.ID_cliente WHERE movimenti.ID_cliente = 1;
+----+---------------------+----------+-------+---------+------------------------+---------+
| ID | data | valuta | nome | cognome | descrizione | tipo |
+----+---------------------+----------+-------+---------+------------------------+---------+
| 1 | 2008-08-09 09:00:00 | 2500.000 | Mario | Rossi | Versamento in contanti | entrata |
| 2 | 2008-08-10 09:00:00 | 2500.000 | Mario | Rossi | bonifico | uscita |
| 3 | 2008-08-11 09:00:00 | 4500.000 | Mario | Rossi | assegno | uscita |
+----+---------------------+----------+-------+---------+------------------------+---------+
3 rows in set (0.00 sec)
A questo punto potrebbe essere utile calcolare i movimenti debitori ed i movimenti creditori di Mario Rossi. Tenendo sempre a mente che l'ID del cliente è 1, la query diventerebbe:
SELECT SUM(movimenti.valuta) AS debitori FROM clienti JOIN movimenti ON (clienti.ID=movimenti.ID_cliente) JOIN tipi_movimento ON (movimenti.tipo=tipi_movimento.ID) WHERE (tipi_movimento.tipo = 'uscita' AND ID_cliente = '1') GROUP BY tipi_movimento.tipo;
+----------+
| debitori |
+----------+
| 7000.000 |
+----------+
1 row in set (0.00 sec)
E, di conseguenza, i relativi movimenti creditori.
SELECT SUM(movimenti.valuta) AS creditori FROM clienti JOIN movimenti ON (clienti.ID=movimenti.ID_cliente) JOIN tipi_movimento ON (movimenti.tipo=tipi_movimento.ID) WHERE (tipi_movimento.tipo = 'entrata' AND ID_cliente = '1') GROUP BY tipi_movimento.tipo;
+-----------+
| creditori |
+-----------+
| 2500.000 |
+-----------+
1 row in set (0.00 sec)
Da notare come si è reso necessario utilizzare l'istruzione di raggruppamento GROUP BY in quanto è stata proposta una funzione SUM();