10. Esercizio [IMPOTS] con MySQL
![]() |
10.1. Trasferimento di un file di testo in una tabella MySQL
Lo script che seguirà trasferirà i dati dal seguente file di testo:
12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:272.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062
nella tabella [impots] del database MySQL [dbimpots]:
![]() |
La connessione al database [dbimpots] avverrà con le credenziali (root,"").
Utilizzeremo la seguente struttura:
![]() |
Lo script [console] che scriveremo utilizzerà la classe [ImpotsFile] per accedere ai dati del file di testo. L'accesso in scrittura al database avverrà tramite i metodi visti in precedenza.
Il codice dello script è il seguente:
# -*- coding=utf-8 -*-
# importazione del modulo delle classi Impostazioni
from impots import *
import re
# --------------------------------------------------------------------------
def copyToMysql(limites,coeffR,coeffN,HOTE,USER,PWD,BASE,TABLE):
# copia le 3 tabelle numeriche dei limiti, coeffR, coeffN
# nella tabella TABLE del database MySQL BASE
# il database MySQL si trova sul computer HOTE
# l'utente è identificato da USER e PWD
# si inseriscono le query SQL in un elenco
# eliminazione della tabella
requetes=["drop table %s" % (TABLE)]
# creazione della tabella
requete="create table %s (limites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2))" % (TABLE)
requetes.append(requete)
# compilazione
for i in range(len(limites)):
# query di inserimento
requetes.append("insert into %s (limites,coeffR,coeffN) values (%s,%s,%s)" % (TABLE,limites[i],coeffR[i],coeffN[i]))
# si eseguono i comandi SQL
return executerCommandes(HOTE,USER,PWD,BASE,requetes,False,False)
def executerCommandes(HOTE,ID,PWD,BASE,requetes,suivi=False,arret=True):
# utilizza la connessione (HOTE,ID,PWD,BASE)
# esegue su questa connessione i comandi SQL contenuti nell'elenco delle richieste
# se monitoraggio=True, allora ogni esecuzione di un comando SQL viene seguita da una visualizzazione che ne indica il successo o il fallimento
# se «arresto=False», la funzione si interrompe al primo errore riscontrato; in caso contrario, esegue tutti i comandi SQL
# la funzione restituisce un elenco (numero di errori, errore1, errore2, ...)
# connessione
try:
connexion=MySQLdb.connect(host=HOTE,user=ID,passwd=PWD,db=BASE)
except MySQLdb.OperationalError,erreur:
return [1,"Erreur lors de la connexion a MySQL sous l'identite (%s,%s,%s,%s) : %s" % (HOTE, ID, PWD, BASE, erreur)]
# si richiede un cursore
curseur=connexion.cursor()
# esecuzione delle query SQL contenute nell'elenco delle query
# vengono eseguite - inizialmente nessun errore
erreurs=[0]
for i in range(len(requetes)):
# si inserisce la richiesta in una variabile locale
requete=requetes[i]
# la query è vuota?
if re.match(r"^\s*$",requete):
continue
# esecuzione della query i
erreur=""
try:
curseur.execute(requete)
except Exception, erreur:
pass
# si è verificato un errore?
if erreur:
# un altro errore
erreurs[0]+=1
# messaggio di errore
msg="%s : Erreur (%s)" % (requete[0:len(requete)-1],erreur)
erreurs.append(msg)
# monitoraggio dello schermo o no?
if suivi:
print msg
# ci si ferma?
if arret:
return erreurs
else:
if suivi:
# visualizziamo la query senza il carattere di fine riga
print "%s : Execution reussie" % (cutNewLineChar(requete))
# informazioni sul risultato della richiesta eseguita
afficherInfos(curseur)
# chiusura della connessione
try:
connexion.commit()
connexion.close()
except MySQLdb.OperationalError,erreur:
# un altro errore
erreurs[0]+=1
# messaggio di errore
msg="%s : Erreur (%s)" % (requete,erreur)
erreurs.append(msg)
# ritorno
return erreurs
# ------------------------------------------------ main
# identità dell'utente
USER="root"
PWD=""
# il computer host del SGBD
HOTE="localhost"
# identificativo del database
BASE="dbimpots"
# identità della tabella dei dati
TABLE="impots"
# il file dei dati
IMPOTS="impots.txt"
# istanza del livello [dao]
try:
dao=ImpotsFile(IMPOTS)
except (IOError, ImpotsError) as infos:
print ("Une erreur s'est produite : {0}".format(infos))
sys.exit()
# si trasferiscono i dati recuperati in una tabella MySQL
erreurs=copyToMysql(dao.limites,dao.coeffR,dao.coeffN,HOTE,USER,PWD,BASE,TABLE)
if erreurs[0]:
for i in range(1,len(erreurs)):
print erreurs[i]
else:
print "Transfert opere"
# fine
sys.exit()
Note:
- righe 106-110: si istanzia la classe [ImpotsFile] presentata nel paragrafo 8.1;
- riga 113: gli array limites, coeffR, coeffN vengono trasferiti in un array MySQL;
- riga 8: la funzione copyToMysql esegue tale trasferimento. La funzione copyToMysql crea un array delle query da eseguire e le fa eseguire dalla funzione executerCommandes, riga 25;
- righe 28-89: la funzione executerCommandes è quella già presentata in precedenza, al paragrafo 9.7, con una differenza: invece di trovarsi in un file di testo, le query sono contenute in un elenco;
Il file di testo impots.txt:
12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:272.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062
Risultati sullo schermo:
Verifica con phpMyAdmin:
![]() |
10.2. Il programma di calcolo delle imposte
Ora che i dati necessari per il calcolo dell'imposta sono in un database, possiamo scrivere lo script per il calcolo dell'imposta. Utilizziamo nuovamente un'architettura a tre livelli:
![]() |
Il nuovo livello [dao] sarà collegato a SGBD e MySQL e sarà implementato dalla classe [ImpotsMySQL]. Esso offrirà al livello [metier] la stessa interfaccia di prima, costituita dall’unico metodo getData che restituisce la tupla (limiti, coeffR, coeffN). Pertanto, il livello [metier] non subirà modifiche rispetto alla versione precedente.
10.3. La classe [ImpotsMySQL]
Il livello [dao] è ora implementato dalla seguente classe [ImpotsMySQL] (file impots.py):
class ImpotsMySQL:
# costruttore
def __init__(self,HOTE,USER,PWD,BASE,TABLE):
# inizializza gli attributi limite, coeffR, coeffN
# i dati necessari per il calcolo dell'imposta sono stati inseriti nella tabella mysqL TABLE
# appartenente al database BASE. La tabella presenta la seguente struttura
# limiti decimal(10,2), coeffR decimal(10,2), coeffN decimal(10,2)
# la connessione al database MySQL del server HOTE avviene con le credenziali (USER,PWD)
# genera un'eccezione in caso di errore
# connessione al database MySQL
connexion=MySQLdb.connect(host=HOTE,user=USER,passwd=PWD,db=BASE)
# viene richiesto un cursore
curseur=connexion.cursor()
# lettura in blocco della tabella TABLE
requete="select limites,coeffR,coeffN from %s" % (TABLE)
# esegue la query [requete] sul database [base] della connessione [connexion]
curseur.execute(requete)
# elaborazione del risultato della query
ligne=curseur.fetchone()
self.limites=[]
self.coeffR=[]
self.coeffN=[]
while(ligne):
# riga corrente
self.limites.append(ligne[0])
self.coeffR.append(ligne[1])
self.coeffN.append(ligne[2])
# riga successiva
ligne=curseur.fetchone()
# disconnessione
connexion.close()
def getData(self):
return (self.limites, self.coeffR, self.coeffN)
Note:
- riga 18: la richiesta SQL SELECT che richiede i dati dal database MySQL. Le righe risultanti da SELECT vengono quindi elaborate una per una da [curseur.fetchone] (righe 22 e 32) per creare le tabelle limites, coeffR, coeffN (righe 28-30);
- il metodo getData dell'interfaccia del livello [dao].
10.4. Lo script della console
Il codice dello script da console (impots_04) è il seguente:
# -*- coding=utf-8 -*-
# importazione del modulo delle classi Impostazioni*
from impots import *
# ------------------------------------------------ main
# l'identità dell'utente
USER="root"
PWD=""
# il computer host del SGBD
HOTE="localhost"
# identificativo del database
BASE="dbimpots"
# identificativo della tabella dei dati
TABLE="impots"
# file di input
DATA="data.txt"
# file di output
RESULTATS="resultats.txt"
# istanza del livello [metier]
try:
metier=ImpotsMetier(ImpotsMySQL(HOTE,USER,PWD,BASE,TABLE))
except (IOError, ImpotsError) as infos:
print ("Une erreur s'est produite : {0}".format(infos))
sys.exit()
# i dati necessari per il calcolo dell'imposta sono stati inseriti nel file IMPOTS
# con una riga per ogni tabella nella forma
# val1:val2:val3,...
# lettura dei dati
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# apertura del file dei risultati
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# utilità
u=Utilitaires()
# si elabora la riga corrente del file dei dati
ligne=data.readline()
while(ligne != ''):
# si rimuove l'eventuale carattere di fine riga
ligne=u.cutNewLineChar(ligne)
# si recuperano i 3 campi coniuge:figli:stipendio che compongono la riga
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# si calcola l’imposta
impot=metier.calculer(marie,enfants,salaire)
# si inserisce il risultato
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# si legge una nuova riga
ligne=data.readline()
# si chiudono i file
data.close()
resultats.close()
Note:
- riga 23: istanziazione dei livelli [dao] e [metier];
- il resto del codice è noto.
Gli stessi delle versioni precedenti dell'esercizio.



