Tables

1.1 Cos'è un ID? Contatori, numeri, e altro.
  Emanuele Cesena
L'ID (o 'Chiave Primaria', o 'Primary Key') è uno strumento essenziale nella creazione di un database.
Come ogni cosa importante, presenta tutta una serie di problemi legati al suo utilizzo, quali ad esempio la scelta del tipo di dato, una formattazione particolare, ecc.
Con questo mini HOWTO cerchero', per quanto mi sia possibile, di chiarire alcuni concetti "chiave" (permettetemi il gioco di parole) relativi all'utilizzo di ID.
Dapprima illustrerò la "parte teorica" (pacco), dopo di chè vedremo un paio di esempi pratici. Per questo ho allegato a questo mini HOWTO un piccolo dbase in formato MS Access 97.

1. Cos'è un ID, o Chiave Primaria qual_dir_si_voglia
Innanzitutto mi preme sottolineare che quelle che in Access vengono definite Chiavi Primarie, piu' in generale (anche in altri campi), vengono semplicemente chiamati ID (che starà per Identifier Dqualcosa :) ). Orbene io li chiamero' piu' semplicemente ID (perchè è piu' corto).
Vediamo subito cos'è un ID. L'ID è un campo che permette di identificare _univocamente_ un record.
Di solito, vuoi per comodità, vuoi perchè occupa meno memoria, si utilizza come ID un numeri intero lungo, progressivo, ma soprattutto che sia diverso per ogni record.
L'utilizzo di un ID numerico è comunque solo una comodità, nulla ci vieta di usare come ID una stringa, o un campo data/ora :-)
Vedremo piu' avanti anche un esempio di ID in forma di stringa.

1.1 Perchè si usano gli ID
Ma praticamente a cosa servono gli ID?? E' molto semplice: ad evitare ripetizioni e ridondanze di dati.
Facciamo un piccolo esempio, per chiarire un concetto che comunque è semplicissimo:
il nostro id.mdb serve per la gestione del fatturato di un'azienda. Tale azienda decide di suddividere le sue fatture in diverse categorie:
- Materie Prime
- Personale
- Straordinari
- Imprevisti
dobbiamo quindi inserire nella tabella tbl_fatture, oltre ai soliti campi: [saldo], [data], [descrizione]... un campo [categoria].

La struttura della tabella risulterà a seguente:
 tbl_fatture
 [saldo] numerico o valuta
 [data] data/ora
 [descrizione] memo
 [categoria] stringa

ovviamente i campi [categoria], nei diversi record, risulteranno ripetitivi e ridondanti.
Per questo è comodo modificare il formato di [categoria] in "numerico" (intero lungo), e costruire un'altra tabella siffatta:

 tbl_categorie
 [IDcateg] contatore
 [categoria] stringa

 tbl_fatture
 [saldo] numerico o valuta
 [data] data/ora
 [descrizione] memo
 [IDcateg] numerico

ora non resta che applicare un join con Integrità Referenziale tra gli [IDcateg] delle 2 tabelle, ed il gioco è fatto!
NB: per visualizzare un elenco completo di ogni spesa con la sua categoria (in parola), basta una semplice query :-)
Come si capisce bene dall'esempio, è essenziale che ad ogni [categoria] venga assegnato un [IDcateg] distinto, altrimenti non è possibile risalire alla categoria di una spesa :-)

2. Formati per gli ID
Vedremo in questo paragrafo alcuni formati tra i piu' diffusi e comodi per gestire gli ID in Access, compresi i loro vantaggi/svantaggi

2.1. Contatori
Access prevede un formato standard per gli ID, ossia il Contatore.
Il contatore non è nient'altro che un numero intero lungo autoincrementante, che non puo' essere modificato dall'utente, ma viene generato automaticamente in fase di immissione di un nuovo record.
Che bello, direte: se è tutto cosi' semplice, perchè hai scritto questo documento?? Ebbene, perchè non è tutto cosi' semplice!! :-)
I problemi nascono un po' piu' avanti... quando vogliamo cancellare...
Vi accorgerete infatti che, cancellando un record (ad esempio 'Personale') rimane un "buco" negli ID:

 tbl_categorie:
 1 Materie Prime
 2 Personale
 3 Straordinari
 4 Imprevisti

Cancellando 'personale', otteniamo:

 tbl_categorie:
 1 Materie Prime
 3 Straordinari
 4 Imprevisti

Se ci riflettete un momento, questo è ovvio: spostando a '2' 'Straordinari', dovremmo aggiornare tutti i dati nel dbase...
Tutti gli [IDcateg] pari a 3, dovrebbero essere modificati in '2'... troppo casino! :-)

Un'altra cosetta un po' piu' spiacevole, si ottiene quando si cancella l'ultimo dato 'Imprevisti': inserendone uno nuovo, questo avrà ID pari a 5!! Sembra che Access si sia dimenticato che l'abbiamo cancellato!

 tbl_categorie:
 1 Materie Prime
 3 Straordinari
 4 Imprevisti

Cancellando 'Imprevisti' ed aggiungendo 'Ammortamento' otteniamo:

 tbl_categorie:
 1 Materie Prime
 3 Straordinari
 5 Ammortamento

Quest'ultimo problema è comunque risolubile, compattando il dbase.
Pero' non è tanto comodo compattare ogni volta che un utente cancella un record... :-)

2.2. ID numerico
Teniamo sempre d'occhio l'ultimo problema presentato, quello dell'ID che viene incrementato anche quando non è necessario.
Per risolvere questo inconveniente, molti programmatori adottano una semplice soluzione: utilizzano come ID un semplice numero (intero lungo).
Cosa succede: quando viene inserito un nuovo record si ricerca l'ID dell'ultimo record, e vi si aggiunge 1.
Semplicissimo! :-) (c'è, ovviamente, l'esempio pratico in id.mdb)
Pero' occorre fare molta attenzione: se per caso qualcosa dovesse andare storto, ci ritroveremmo con una relazione [ID] [dato] non piu' biunivoca, e quindi inapplicabile!
Un'altro inconveniente: i contatori non potevano essere modificati dall'utente. Gli ID numerici si'!!
Attenzione dunque all'utente inesperto che "vedendo un buco" modifica il nostro [IDcateg] di 'Straordinari' a 2 :-) (e poi ovviamente perde i dati e tocca a noi metter a posto!) :-))

2.3. ID numerici "anti buco"
Rimane ancora pero' il problema dei buchi... a qualcuno potrebbero dare fastidio :-)
Ebbene, possiamo trovare una soluzione anche a questo problema, con una semplice modifica nell nostra funzione di "aggiornamento ID". Vediamo, passo passo, cosa faceva e cosa farà ora:

 prima:
 ' apre la tabella
 ' prende l'ID dell'ultimo record
 ' aggiunge 1
 ' inserisce il nuovo ID

 ora:
 ' apre la tabella
 ' ID = 0
 ' label: ID = ID + 1
 ' scorre la tabella
 ' c'è già questo ID??
 ' Si', torna a label:
 ' inserisci il nuovo ID

Pensate pero' a cosa succede se ci sono molti record, e addirittura se gli ID fossero già ordinati: sarebbe un'inutile spreco di tempo!

2.4. Tabelle temporanee
Si puo' ovviare il problema della perdita di tempo, con qualche stratagemma ingegnoso.
Per questo ci avvaliamo di una tabella temporanea.

 * possiamo ad esempio salvarci l'ID di tutti i record che cancelliamo.
 In questo modo abbiamo un elenco di ID non piu' in uso, e basta ogni volta prendere il primo record di questa tabella, ed inserirlo come ID.

3. ID non numerici
Talvolta puo' essere comodo utilizzare ID non numerici, ad esempio delle stringhe particolari, come potrebbe essere un: "NNNN-AA" come ID per una fattura, dove NNNN è il numero della fattura, AA l'anno di rilascio.
A mio parere questa non è una soluzione brillante, perchè limita la velocità nelle ricerche (infatti le operazioni su stringhe sono molto piu' lente di quelle su numeri), ma visto che è un problema ricorrente, ho pensato di inserirne una possibile soluzione in id.mdb.
Ovviamente il sistema è lo stesso definito in nel par. 2.2., ossia:

 ' apro la tabella
 ' calcolo l'ID
 ' inserisco il nuovo ID

Bisogna stare molto attenti al fatto che l'ID sia sempre e comunque _univoco_!!

3.1. Utilizzo di tabelle di appoggio
Per completare l'esempio, abbiamo supposto di voler costruire un ID di questo tipo: "NNNN-AA".
Pero' NNNN è un numero progressivo, ma che deve essere azzerato ogni anno.
Allora possiamo sfruttare una soluzione intelligente: salviamo tutti gli NNNN che inseriamo in una tabella di appoggio.
In questo modo, tenendo sempre conto del fatto che non vogliamo buchi, avremo a disposizione 3 tabelle (tutto solo per un ID... :) ):

 - tabella dei dati
 - tabella di appoggio (con gli NNNN)
 - tabella temporanea (con gli NNNN cancellati)
 (per comodità, mi sono limitato a mostrarvi la formattazione: per l'"anti buchi" avete già un altro esempio)

E la nostra povera funzione dovrà:

 ' aprire la tabella temporanea.
 ' se non è vuota, prende come ID il primo NNNN
 ' se invece è vuota:
  ' apre la tabella di appoggio
  ' prende l'ultimo NNNN
  ' prende come ID questo NNNN + 1
 ' end se :)
 ' aggiunge all'ID la stringa "-AA"
 ' salva l'ID

E' molto macchinoso, ma il bello viene ora: per azzerare gli NNNN (a inizio nuovo anno) basta cancellare i record della tabella di appoggio! :-)

Download:
 
  IDema.zip (26Kb)


Se pensate di avere del materiale freeware interessante e volete pubblicarlo, allora leggete qui.