Capitolo 02
Entità e attributi
All models are wrong, but some are useful.
Le tre tabelle della lezione precedente le avete trovate già pronte, con le colonne decise. Prima che esistessero però, qualcuno ha dovuto stabilire che il registro dei punti avesse bisogno di tre tabelle e non di due o di cinque, che la casa fosse una colonna della tabella studente, eccetera. Questo capitolo si occupa di quelle decisioni, che vanno effettuate prima delle tabelle: quali cose il database deve conservare, e che cosa deve conservare di ciascuna.
La parte di mondo di cui un database conserva i dati si chiama dominio: per il registro dei punti, il dominio è Hogwarts, con i suoi studenti, le sue case e i suoi professori. Un modello concettuale è la descrizione di un dominio che stabilisce quali cose vanno registrate, quali informazioni conservare su ciascuna e come le cose sono legate fra loro, senza ancora dire come i dati saranno memorizzati.
Il modello concettuale più usato è il modello Entità-Associazione (in inglese Entity-Relationship, da cui la sigla E/R), che descrive il dominio con entità, attributi e associazioni, e lo disegna in un diagramma. L’inglese relationship in italiano si può tradurre anche con “relazione”, ma in questo libro diciamo “associazione”: nel capitolo 3 la parola “relazione” sarà il nome tecnico della tabella.
Una casa che è solo un nome
Nella tabella studente della lezione precedente la casa è una colonna di testo: per il database Grifondoro è la parola Grifondoro, scritta accanto al nome di ogni studente della casa. Finché le domande riguardano gli studenti, una parola basta. Ora, però, immaginiamo che la professoressa McGonagall chieda di registrare anche i colori e l’animale dello stemma di ogni casa, che servono per gli stendardi del banchetto di fine anno.
Con le tabelle che abbiamo, l’unico posto in cui scrivere colori e animale è la tabella studente, con due colonne nuove: colori_casa e animale_casa. Chiamiamo questa la prima versione delle tabelle. Il blocco qui sotto mostra la tabella studente con le due colonne aggiunte.
I colori di Grifondoro, rosso e oro, sono scritti sei volte, una per ogni studente della casa, e il leone altrettante. Riconoscerai sicuramente la ridondanza della seconda lezione del capitolo 1: ad esempio, per cambiare i colori di Grifondoro bisogna correggere sei righe! Una riga dimenticata basta a dare alla casa due coppie di colori.
C’è anche un difetto meno visibile. Padma Patil è l’unica studentessa di Corvonero nella tabella. Il blocco qui sotto contiene due istruzioni, che si leggono come frasi: cancella (DELETE) dalla tabella studente la riga in cui il nome è Padma Patil; poi elenca casa, colori e animale che compaiono nella tabella studente, ogni combinazione una volta sola (DISTINCT). Prima di eseguire il blocco, prova a prevedere quante case elenca la seconda istruzione.
DELETE FROM studente WHERE nome = 'Padma Patil';
SELECT DISTINCT casa, colori_casa, animale_casa FROM studente;
Nessuna istruzione ha cancellato Corvonero. Il problema è che nella tabella studente una casa non ha un posto suo: esiste finché almeno uno studente la nomina. Questa è l’anomalia di cancellazione della seconda lezione del capitolo 1, e anche allora c’era di mezzo Padma, che a quanto pare non riesce a uscire dall’archivio senza portarsi via qualcuno: con la sua unica assegnazione era sparito Flitwick. Per lo stesso motivo una casa senza studenti non si può registrare, ed è l’anomalia di inserimento.
Nel pannello “Database” della colonna di destra la riga di Padma compare segnata come tolta. Come nella lezione precedente, ogni blocco di istruzioni riparte comunque dalle tabelle iniziali.
La casa come entità
Colori e animale sono informazioni sulla casa, e le abbiamo messe nella tabella studente: ogni riga della tabella studente adesso parla di due cose diverse, lo studente e la sua casa. Nella seconda versione delle tabelle la casa ha una tabella propria, casa, con nome, colori e animale, mostrata qui sotto. La tabella studente torna ad avere nome, casa e anno, e nella colonna casa c’è soltanto il nome, che rimanda a una riga della tabella casa.
I colori di Grifondoro adesso sono scritti una volta sola. Il blocco qui sotto esegue sulla seconda versione la stessa cancellazione di prima, e poi elenca la tabella casa.
DELETE FROM studente WHERE nome = 'Padma Patil';
SELECT * FROM casa;
Le case restano quattro. Corvonero è una riga della tabella casa, e la riga di Padma nella tabella studente la nominava soltanto: cancellando Padma, Corvonero non perde niente. Anche una casa ancora senza studenti si può registrare, con una riga nella tabella casa.
Nella seconda versione la casa è un’entità; nella prima era un attributo dello studente.
Se hai già scritto classi in Python, la coppia entità e occorrenza ti ricorda la coppia classe e istanza, con una differenza: un’entità ha attributi e nessun metodo. Che cosa fare con i dati lo stabilisce chi scrive i programmi che usano il database.
La casa è diventata un’entità per due motivi, e sono anche il criterio per decidere. Chi usa il database vuole sapere della casa qualcosa oltre al nome: i colori e l’animale. Inoltre una casa esiste anche senza studenti: Corvonero resta una casa di Hogwarts anche quando Padma non c’è più. Una cosa che soddisfa queste due condizioni è un’entità; una cosa di cui interessa soltanto il valore è un attributo. Il criterio quindi dipende dalle domande a cui il database deve rispondere, e non dalla cosa in sé. Nel registro dei punti del capitolo 1 nessuno chiedeva i colori delle case, e la casa come colonna di testo andava bene: è diventata una scelta sbagliata quando McGonagall ha fatto una domanda nuova.
Resta la colonna casa della tabella studente, che collega ogni studente alla sua casa. Nel modello E/R quel collegamento non è un attributo dello studente: è un’associazione fra due entità, e la vedremo nella prossima lezione.
L’errore opposto
Il criterio non dice di fare di ogni cosa un’entità. Proviamo con l’anno di corso. Potremmo dargli una tabella propria, anno, con una sola colonna numero e le righe da 1 a 7, e nella tabella studente la colonna anno rimanderebbe a una di quelle righe. Le tabelle funzionano, ma la tabella anno non contiene niente che la colonna anno di studente non contenesse già: aggiunge una tabella da tenere aggiornata, sette righe che cambieranno solo il giorno in cui Hogwarts aprirà un ottavo anno, e nessuna informazione. Di un anno di corso, in questo dominio, interessa soltanto il numero: l’anno è un attributo dello studente.
In un altro dominio la stessa cosa può diventare un’entità. Nel registro di una scuola italiana la classe di uno studente, per esempio la 3A, è un attributo finché interessa solo la sigla; se la scuola vuole sapere anche l’aula e il coordinatore di ogni classe, la classe diventa un’entità. Nessun modello registra tutto di un dominio: il nostro non dice niente dei fondatori delle case né dei loro fantasmi. È il senso della frase di Box in cima alla pagina: un modello è utile se risponde alle domande per cui è stato costruito.
Sono segnali, non regole: un’entità con un solo attributo può servire, se esiste per conto proprio e se chi usa il database ne vorrà sapere altro.
Il direttore di una casa, per esempio McGonagall per Grifondoro, non ricade in nessuno dei due segnali. Il direttore non è un attributo della casa, perché è un professore, e di un professore interessano il nome, la materia e i punti che assegna. Non serve nemmeno un’entità nuova, perché nel registro dei punti la tabella professore c’è già. Il direttore è un legame fra due entità che esistono già, la casa e il professore: è un’associazione, ed è l’argomento della prossima lezione.
Disegnare entità e attributi
Un modello E/R si disegna. Nei diagrammi di questo libro un’entità è un rettangolo con il nome al centro, e un attributo è un segmento che esce dal rettangolo e finisce in un piccolo cerchio, con il nome accanto. Prima di disegnare lo studente servono due decisioni.
La prima riguarda il nome. Nella tabella studente il nome è un solo testo, Fred Weasley. Se il database deve rispondere alla domanda “quanti Weasley ci sono a Hogwarts?”, un solo testo non basta: per contare i Weasley bisognerebbe tagliare ogni nome dopo lo spazio. Nel file studenti.json, che trovi nel pannello “Archivio”, i Weasley sono tre: Ron, Fred e George. Negli anni da Hogwarts passano anche Percy e Ginny, e prima di loro Bill e Charlie: con i Weasley la domanda non è mai oziosa. Perché il conto si faccia senza tagliare i testi, il cognome deve essere un dato a sé.
Un attributo composto è un attributo formato da più parti, ognuna con un significato proprio: il nominativo di uno studente, cioè il nome completo, è formato da nome e cognome. Se nessuno chiedesse dei cognomi, il nominativo potrebbe restare un solo testo.
La seconda riguarda le informazioni che non tutti hanno. Supponiamo di voler registrare il Patronus di ogni studente. Harry evoca il suo, un cervo, al terzo anno, e quasi nessuno studente del primo anno ne ha uno: al primo anno si fatica già a far volare una piuma. Un attributo opzionale è un attributo che per alcune occorrenze può non avere un valore. Nel diagramma un attributo opzionale porta il segno (0,1) accanto al nome: il primo numero è il minimo dei valori che può avere, il secondo il massimo, quindi nessun valore oppure uno. Nelle tabelle il valore che manca ha un nome e un comportamento tutto suo, NULL, e lo vedremo nella lezione “Il valore che non c’è”, nel capitolo 3.
Il diagramma qui sotto mostra le due entità di questa lezione, con l’attributo composto nominativo disegnato come un’ellisse da cui escono le sue parti.
Nel diagramma mancano due cose. La colonna casa non compare fra gli attributi di studente, e le due entità non sono collegate: il legame fra uno studente e la sua casa è un’associazione, e il rombo che la disegna arriva nella prossima lezione. Inoltre tutti i cerchi sono vuoti. Un cerchio pieno segna l’attributo che distingue un’occorrenza da tutte le altre, e quale attributo distingua davvero uno studente è il problema lasciato aperto nella lezione precedente: lo risolveremo più avanti in questo capitolo, nella lezione “Identificare senza ambiguità: le chiavi”.
Un attributo derivato è ridondanza con un’altra forma. Per questo nei diagrammi di questo libro gli attributi derivati non compaiono: quando servono, si calcolano.
Un testo descrive il dominio così: “A Hogwarts ogni studente ha un nome e frequenta un anno di corso, dal primo al settimo.” Un compagno disegna tre entità: studente, nome e anno. Che cosa non va?
Un database deve rispondere a una sola domanda sulle bacchette: di che legno è quella di ogni studente. Un compagno crea l’entità bacchetta con il solo attributo legno. Che cosa ne pensi?
Un compagno propone di aggiungere all’entità casa l’attributo totale_punti, così la classifica si legge senza fare calcoli. Che cosa succede?