Newsgroup: it.comp.lang.visual-basic
Titolo: Coerenza Dati

Ciao a tutti,
sto sviluppando un gestionale in Visual Basic e, durante l'analisi
delle funzioni del software, sono rimasto folgorato da un problema.
Per circoscrivere il problema, mettiamo che il nostro software abbia
solo due sezioni: clienti e fatture.
Supponiamo inoltre che la fattura consista soltanto nei dati del
cliente (sempre per semplificare il problema) e che non ci siano altri
dati (data, ora, prodotti acquistati dal cliente ...).
Supponiamo, infine, che le due tabelle del db che si occuperanno dei
clienti e delle fatture abbiano ciascuna un campo univoco (id) che si
autoincrementa per poter distinguere le diverse righe di ciascuna
tabella del db.
Dopo tutte queste premesse, veniamo al dunque.
Clienti e fatture possono essere o meno legate tra di loro.
Infatti, in fase di registrazione della fattura nella tabella fatture
possiamo:
1) memorizzare l'id del cliente a cui si sta facendo la fattura
direttamente nella tabella fatture;
2) registrare direttamente nella tabella delle fatture i dati del
cliente (quindi in definitiva aggiungere i campi della tabella clienti
nella tabella fornitori)
A prima vista la soluzione 1) sembrerebbe la migliore, visto che evito
la ridondanza dei campi delle tabella clienti nella tabella fatture e,
soprattutto, se devo aggiungere a posteriori un campo nella tabella
clienti, non devo far nessun'altra modifica nella tabella fatture per
avere a disposizione questo nuovo campo anche nelle fatture.
Pero', ed è un pero' abbastanza sostanzioso, se utilizzo la soluzione
1) ci sono problemi di coerenza di dati.
Infatti, se modifico i dati del cliente, utilizzando la soluzione 1),
automaticamente tutte le fatture relative (anche quelle precedenti alla
modifica, ovviamente) al cliente con quell'id specifico, cambiaranno
tutte per i dati variati. E questo non va bene.
A questo punto ho pensato di risolvere il problema in questo modo:
Invece di strutturare la tabella clienti così:
+ id
+ nome
+ cognome
+ indirizzo
...
separo la tabella clienti in due tabelle:
TABELLA CLIENTI
+ id
+ id_dettagli (legato all'id della tabella seguente CLIENTI_DETTAGLI)
TABELLA CLIENTI_DETTAGLI
+ id
+ data_inserimento_dettaglio
+ nome
+ cognome
+ indirizzo
Da notare che ho aggiunto nella tabella CLIENTI_DETTAGLI anche il campo
data_inserimento_dettaglio che riporta la data in cui è stata
effettuata la modifica della scheda del cliente.
In questo modo, nella tabella fatture non cambia nulla (si fa sempre
riferimento allo stesso id del cliente), pero' la data della fattura
sarà decisiva per capire quale specifico dettaglio del cliente
prendere.
Inoltre, in questo modo, avrò anche uno storico delle modifiche
effettuate alla scheda del cliente (se può essere utile).
Questo è un problema abbastanza ricorrente (pensate al "magazzino", in
cui l'importo di un prodotto può cambiare ... cosa succede a tutte le
fatture che fanno riferimento all'id di quel prodotto?!?!?) , per cui
mi piacerebbe trovare
la soluzione più generale possibile.
Voi come risolvete il problema?

 Voi come risolvete il problema?
Dai un'occhiata qui: 
www.fatturafast.org
Ci sono i sorgenti completi di un piccolo gestionale in VB6 (fatture, ddt, 
anagrafica, clienti, fornitori, magazzino...)
ciao!
-- 
Gianluca Cannalire
Microsoft MVP/MCP - Visual Basic
http://www.visual-basic.it
http://community.visual-basic.it/gianluca

Per la serie "La verità sta nel mezzo" :)
Nel senso che per ogni cliente ci sono comunque delle informazioni 
basilari che non cambiano (cognome, nome, codice_fiscale, data_nascita, 
ecc.) e altre che possono cambiare col tempo e vanno memorizzate in ogni 
fattura.
Poi ci sono dei dettagli che, giustamente, possono cambiare con il tempo.
A questo punto però poco ti importa di dover tornare indietro negli anni 
e sapere esattamente tutte le informazioni di quei tempi.
Supponiamo che la tabella clienti sia così strutturata:
CLIENTI
.......
Codice_Fiscale (primario),
Cognome,
Nome,
Data_Nascita,
Residenza,
Indirizzo_Residenza,
Tel_Fisso,
Tel_Mobile1,
Tel_Mobile2
la tabella fatture dovrebbe essere (IMHO) composta così:
FATTURE
.......
Progressivo_Fattura (primario),
Codice_Fiscale,
Residenza,
Indirizzo_Residenza
ID_Prodotto,
Quantita,
ecc.
Come vedi, i dati basilari del cliente vengono comunque riportati nella 
fattura (e solo quelli fondamentali del cliente, cioè codice_fiscale, 
residenza, indirizzo_residenza) perchè possono variare magari da un anno 
all'altro.
Quindi a questo punto a te può tornare utile sapere se il cliente X 
nell'anno 1982 fosse residente a Taranto piuttosto che a New York.
Ma dubito che possa tornarti utile sapere quale fosse il suo recapito 
telefonico un anno fa. Semmai può tornarti utile sapere attualmente i 
suoi recapiti fissi e mobili (uno storico dei telefoni a che ti 
servirebbe effettivamente?).
Poi ogni caso software è particolare :)
Quello che dici secondo me può essere vero per i prodotti del magazzino.
Cioè se oggi in magazzino ho delle mucche, che vendo a 10 euro l'una, 
non posso creare solo la tabella dei prodotti con il loro bell'ID e i 
dati sul costo al pezzo singolo, e fare riferimento SOLO all'ID nella 
fattura.
Perchè, come notavi giustamente, se ora voglio vedere quante mucche ho 
venduto un anno fa e quanto ci ho guadagnato, farei riferimento ai 
prezzi di ORA, non certo a quelli di allora.
Quindi come si può risolvere questo problema?
IMHO ancora come sopra.
Ogni prodotto ha dei dettagli: che siano essi 10 o 20 o 5, non cambia il 
ragionamento: alcuni sono fondamentali e storico, altri non ti servono 
per la storicità.
Per esempio in una fattura io metterei comunque l'ID del prodotto, la 
quantità venduta, il costo unitario (e già da questi due campi puoi 
calcolarti il totale) e l'eventuale sconto effettuato.
Magari a parità di prodotto, in base alla stagione puoi applicare uno 
sconto del 10% piuttosto che del 15%, però il software a video ti 
PROPONE lo sconto, tu scegli se utilizzare quello o applicarne uno a tuo 
piacere, e nella fattura memorizzi COMUNQUE lo sconto applicato.
Quindi anche per la fattura lato-prodotti ci sono dei campi che sono 
fondamentali per la storicità, altri che non lo sono.
La ridondanza dei campi di cui parli non è quella relativa all'inserire 
alcune colonne ANCHE in altre tabelle; si parla di ridondanza vera e 
propria quando inserisci in più tabelle le colonne i cui valori non 
varieranno mai (pensa se in ogni fattura memorizzassi anche il codice 
fiscale del cliente, o magari oltre a quantità e costo unitario anche il 
totale).
Se poi vuoi proprio spingerti a creare un'applicazione che permetta 
all'utente di aumentare il numero di dettagli (colonne) per i clienti o 
per i prodotti beh allora il discorso cambia.
Ma se non è quello che intendi, allora tutto questo va stabilito in fase 
di progettazione.
Se ho sbagliato fucilatemi pure :)
-- 
Quando noi ignoranti eravamo di più, tutto era più bello...
(A. Celentano)
Per rispondermi in privato, togli prima l'immondizia dalla testa ;)

Grazie per il link, vado a spulciare i sorgenti



Rimanendo comunque in una pura discussione relativa al numero di campi
da aggiungere, la soluzione che ho proposto è nella maggior parte dei
casi più flessibile.
E cioè ...
Se tu riporti nella tua tabella fatture già più di un campo relativo
alla tabella  clienti, non è più conveniente. Infatti, conoscere l'id
del cliente nella tabella fatture, vuol dire aver rintracciato il
cliente (si ha una maggior garanzia di univocità).
Invece conoscere, per esempio, nome e cognome del cliente nella tabella
fatture, non vuol dire nel 100% dei casi aver rintracciato il cliente
(potrebbero esserci due persone omonime).
Mi piace generalizzare, il più possibile e per quanto possibile. :-D
Insomma tu utilizzi la soluzione di aggiungere dei campi, anche se è
una soluzione ridondante.

 una soluzione ridondante.
Beh a volte la ridondanza torna utile quando la soluzione alternativa 
comincia a richiedere troppi join fra tabelle per risalire ai dati 
integri di cui necessitiamo...


 dati del cliente siano cambiati.
E' una soluzione anche se non del tutto versatile.
Ad esempio, in un mio gestionale per i distributori di carburante, ho 
utilizzato un approccio differente che potrebbe andar bene anche per 
"Negus".
In sostanza, ad ogni variazione di dati dell'anagrafica del cliente, 
provvedo a creare un nuovo record anagrafica legato, tramite l'ID, al 
record 'vecchio'.
Questo è necessario perchè può capitare (e capita anche non di rado) che 
un cliente possa cambiare la ragione sociale, ma mantenere inalterati 
tutti gli altri dati.
Il fatto di legare 'vecchio' e 'nuovo' cliente (che poi, sono la stessa 
cosa, ma con dati anagrafici differenti) mi permette di vedere tutto lo 
storico di vendita a quel determinato cliente a prescindere dalla 
variazione dei dati anagrafici.
Inoltre, non devo duplicare eccessivamente dati all'interno della tabella 
documenti (fatture, conti, ecc. ecc.)
Ciao!


 anagrafica, clienti, fornitori, magazzino...)
Ho controllato i sorgenti ma non mi sembra che faccia alcun controllo
di cambio dati.

 del tempo.
In effetti quello che volevo dire è che la soluzione che ho trovato
complica di poco il programma, però ti dà in ogni momento TUTTI i
dati della tabella a cui si fa riferimento (e, che non guasta, anche il
log delle modifiche). Sai meglio di me quanto questo possa essere
importante, quando il cliente può chiederti, in un  secondo momento,
quel dato specifico che tu non hai registrato.

 documenti (fatture, conti, ecc. ecc.)
Infatti.

 una soluzione ridondante.
Sembra ridondante.
In realtà non è affatto così.
Considera che una fattura è un'entità a se stante e statica, che una volta
creata così resta per sempre.
I dati che inserisci appartengono *di*fatto* alla fattura, e non al cliente.
Noi utilizziamo 3 tabelle per le fatture: testa, righe e coda (i dettagli a
fondo pagina) e obligatoriamente devono portarsi dietro i dati di creazione.
Ciao
--
Reporting tool: 
http://www.neodatatype.net
Qualunque mentecatto può scrivere codice che un computer possa capire.
I buoni programmatori scrivono codice che gli uomini possano capire.
[Martin Fowler]

 anagrafica, clienti, fornitori, magazzino...)
Finalmente č on-line! :)
Vado a vedere.
Interessa ancora l'integrazione della parte di reportistica?


 fondo pagina) e obligatoriamente devono portarsi dietro i dati di creazione.
C'e' comunque ridondanza e spreco di spazio (tanto).
Pensa che cosi' facendo, magari ti porti dietro 5, 10 o forse più
campi del cliente da replicare per ogni fattura. Utilizzando la
soluzione che ho proposto, oltre ad inserire semplicemente
l'id_dettaglio del cliente (e quindi un solo campo integer) con tanto
risparmio di spazio, hai anche lo storico delle modifiche dei dati del
cliente.

 cliente.
Sě, ma attento a fare queste cose.
Metti caso che il nel tuo "storico" del cliente metti il campo "destinazione
merci", e per quella fattura (e solo per quella) ti si chiede di spedirle da
un'altra parte.
Che fai?


 Che fai?
Aspe' aspe' aspe' ...
Non metterei mai (e spero neanche tu!) un campo "destinazione merci"
nell'anagrafica clienti, perchè non è coerente con il tipo di dati
(destinazione merci non c'entra nulla con i dati del cliente) della
tabella clienti.
Il discorso dello "storico" NON è l'obiettivo da raggiungere, ma
semplicemente un valore aggiunto che viene in automatico utilizzando
una tabella a parte per ciascun profilo di uno stesso cliente.
Comunque il campo "destinazione merci" ovviamente lo metterei come
campo della tabella fatture.
Ciao,
  Fabrizio