Tesseramenti del circolo: join, duplicati e vincoli
Un circolo sportivo gestisce i tesseramenti con un database Base creato da un volontario. Le tabelle sono SOCI (IDSocio, Cognome, Nome, CodiceFiscale, IDSquadra), SQUADRE (IDSquadra, Nome, QuotaAnnua) e PAGAMENTI (IDPagamento, IDSocio, Data, Importo). Non esiste alcun vincolo di unicità su CodiceFiscale: dopo tre mesi risultano 7 persone iscritte due volte, con pagamenti registrati su entrambe le schede. Il form di inserimento è usato da tre volontari, ha due pulsanti «Salva» molto vicini e alcuni record vengono inseriti due volte per doppio clic. La query «Totale versato per socio» restituisce 214 righe su 260 soci e, per i soci con due pagamenti, il totale delle quote attese risulta gonfiato. Il direttivo vuole un report per squadra con totale versato e numero di soci morosi, cioè con quota annua non raggiunta.
1. La query restituisce 214 soci su 260 e gonfia le quote. Come va riscritta l'aggregazione e perché si producono i due sintomi?
Read the worked answer
I sintomi hanno cause diverse. Il primo è il join: se nella query si mette un criterio sul campo Data o Importo della tabella PAGAMENTI (per esempio un intervallo di date), il LEFT JOIN diventa di fatto un INNER JOIN e i 46 soci senza pagamenti spariscono: 260 − 46 = 214. La condizione va spostata nella condizione di join o eliminata, e il valore mancante va reso esplicito con COALESCE(SUM(Importo);0).
Il secondo è la granularità. Unendo SOCI a PAGAMENTI si ottiene una riga per pagamento: se nella stessa query si somma anche QuotaAnnua, la quota viene contata una volta per pagamento. Soluzione: creare prima una query «Versamenti per socio» con GROUP BY IDSocio e SUM(Importo), poi unirla a SOCI con LEFT JOIN; la quota si somma in una query per squadra dove c'è una riga per socio. In alternativa si usa una sottoquery nel SQL. Il conteggio finale deve tornare: 260 soci, anche quelli con totale zero.
2. Come impedire nuovi duplicati di CodiceFiscale e come bonificare i 7 già presenti, considerando che il form è usato da tre persone diverse?
Read the worked answer
Il vincolo va messo nel database, non nel form: tre volontari e più percorsi di inserimento non possono dipendere da un controllo applicativo. Prima si bonifica: query GROUP BY CodiceFiscale HAVING COUNT(*) > 1 per elencare i duplicati, scelta della scheda da tenere, spostamento dei pagamenti sull'IDSocio corretto e cancellazione delle altre schede, in una transazione o dopo un backup.
Poi, in modalità struttura della tabella SOCI, si crea un indice univoco su CodiceFiscale (tasto destro > Indici, nuovo indice, proprietà Univoco). Due accorgimenti: normalizzare con UPPER e TRIM, altrimenti «rssmra80a01h501u» e «RSSMRA80A01H501U» passano entrambi; e ricordare che in molti motori un indice univoco ammette più valori NULL, quindi un codice fiscale vuoto non è protetto e va reso obbligatorio.
Il form deve intercettare l'errore di violazione e mostrare un messaggio comprensibile invece dell'errore SQL. Il doppio clic si previene disabilitando il pulsante dopo il primo inserimento, oppure eliminando il secondo pulsante «Salva» e facendo convalidare il record prima della scrittura.